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) {
182 Value visit(
const slang::ast::ElementSelectExpression &expr) {
184 auto value = convertLvalueOrRvalueExpression(expr.value());
189 auto derefType = value.getType();
191 derefType = cast<moore::RefType>(derefType).getNestedType();
193 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType,
194 moore::QueueType, moore::AssocArrayType, moore::StringType>(
196 mlir::emitError(loc) <<
"unsupported expression: element select into "
197 << expr.value().type->toString() <<
"\n";
202 if (isa<moore::AssocArrayType>(derefType)) {
203 auto assocArray = cast<moore::AssocArrayType>(derefType);
204 auto expectedIndexType = assocArray.getIndexType();
210 if (givenIndex.getType() != expectedIndexType) {
212 <<
"Incorrect index type: expected index type of "
213 << expectedIndexType <<
" but was given " << givenIndex.getType();
217 return moore::AssocArrayExtractRefOp::create(
218 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
221 return moore::AssocArrayExtractOp::create(builder, loc, type, value,
226 if (isa<moore::StringType>(derefType)) {
228 mlir::emitError(loc) <<
"string index assignment not supported";
233 auto i32Type = moore::IntType::getInt(builder.getContext(), 32);
239 return moore::StringGetOp::create(builder, loc, value, index);
243 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
244 auto range = expr.value().type->getFixedRange();
245 if (
auto *constValue = expr.selector().getConstant();
246 constValue && constValue->isInteger()) {
247 assert(!constValue->hasUnknown());
248 assert(constValue->size() <= 32);
250 auto lowBit = constValue->integer().as<uint32_t>().value();
252 return llvm::TypeSwitch<Type, Value>(derefType)
253 .Case<moore::QueueType>([&](moore::QueueType) {
255 <<
"Unexpected LValue extract on Queue Type!";
259 return moore::ExtractRefOp::create(builder, loc, resultType,
261 range.translateIndex(lowBit));
264 return llvm::TypeSwitch<Type, Value>(derefType)
265 .Case<moore::QueueType>([&](moore::QueueType) {
267 <<
"Unexpected RValue extract on Queue Type!";
271 return moore::ExtractOp::create(builder, loc, resultType, value,
272 range.translateIndex(lowBit));
279 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
280 if (isa<moore::QueueType>(derefType)) {
283 if (isa<moore::RefType>(value.getType())) {
284 context.
currentQueue = moore::ReadOp::create(builder, loc, value);
295 return llvm::TypeSwitch<Type, Value>(derefType)
296 .Case<moore::QueueType>([&](moore::QueueType) {
297 return moore::DynQueueRefElementOp::create(builder, loc, resultType,
301 return moore::DynExtractRefOp::create(builder, loc, resultType,
306 return llvm::TypeSwitch<Type, Value>(derefType)
307 .Case<moore::QueueType>([&](moore::QueueType) {
308 return moore::DynQueueExtractOp::create(builder, loc, resultType,
309 value, lowBit, lowBit);
312 return moore::DynExtractOp::create(builder, loc, resultType, value,
319 Value visit(
const slang::ast::NullLiteral &expr) {
321 if (isa<moore::ClassHandleType, moore::ChandleType, moore::EventType,
322 moore::NullType>(type))
323 return moore::NullOp::create(builder, loc);
324 mlir::emitError(loc) <<
"No null value definition found for value of type "
330 Value visit(
const slang::ast::RangeSelectExpression &expr) {
332 auto value = convertLvalueOrRvalueExpression(expr.value());
336 auto derefType = value.getType();
338 derefType = cast<moore::RefType>(derefType).getNestedType();
340 if (isa<moore::QueueType>(derefType)) {
341 return handleQueueRangeSelectExpressions(expr, type, value);
343 return handleArrayRangeSelectExpressions(expr, type, value);
348 Value handleQueueRangeSelectExpressions(
349 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
351 llvm::scope_exit restoreQueue([&] { context.
currentQueue = savedQueue; });
357 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
360 mlir::emitError(loc) <<
"queue lvalue range selections are not supported";
363 return moore::DynQueueExtractOp::create(builder, loc, resultType, value,
369 Value handleArrayRangeSelectExpressions(
370 const slang::ast::RangeSelectExpression &expr, Type type, Value value) {
371 std::optional<int32_t> constLeft;
372 std::optional<int32_t> constRight;
373 if (
auto *constant = expr.left().getConstant())
374 constLeft = constant->integer().as<int32_t>();
375 if (
auto *constant = expr.right().getConstant())
376 constRight = constant->integer().as<int32_t>();
382 <<
"unsupported expression: range select with non-constant bounds";
402 int32_t offsetConst = 0;
403 auto range = expr.value().type->getFixedRange();
405 using slang::ast::RangeSelectionKind;
406 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
411 assert(constRight &&
"constness checked in slang");
412 offsetConst = *constRight;
423 offsetConst = *constLeft;
434 int32_t offsetAdd = 0;
439 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
440 range.isLittleEndian()) {
441 assert(constRight &&
"constness checked in slang");
442 offsetAdd = 1 - *constRight;
448 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
449 !range.isLittleEndian()) {
450 assert(constRight &&
"constness checked in slang");
451 offsetAdd = *constRight - 1;
455 if (offsetAdd != 0) {
457 offsetDyn = moore::AddOp::create(
458 builder, loc, offsetDyn,
459 moore::ConstantOp::create(
460 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
464 offsetConst += offsetAdd;
475 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
480 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
483 return moore::DynExtractOp::create(builder, loc, resultType, value,
487 offsetConst = range.translateIndex(offsetConst);
489 return moore::ExtractRefOp::create(builder, loc, resultType, value,
492 return moore::ExtractOp::create(builder, loc, resultType, value,
499 Value visit(
const slang::ast::ConcatenationExpression &expr) {
500 SmallVector<Value> operands;
501 if (expr.type->isString()) {
502 for (
auto *operand : expr.operands()) {
503 assert(!isLvalue &&
"checked by Slang");
504 auto value = convertLvalueOrRvalueExpression(*operand);
508 moore::StringType::get(context.
getContext()), value,
false,
512 operands.push_back(value);
514 return moore::StringConcatOp::create(builder, loc, operands);
516 if (expr.type->isQueue()) {
517 return handleQueueConcat(expr);
519 for (
auto *operand : expr.operands()) {
523 if (operand->type->isVoid())
525 auto value = convertLvalueOrRvalueExpression(*operand);
532 operands.push_back(value);
535 return moore::ConcatRefOp::create(builder, loc, operands);
537 return moore::ConcatOp::create(builder, loc, operands);
544 Value handleQueueConcat(
const slang::ast::ConcatenationExpression &expr) {
545 SmallVector<Value> operands;
548 cast<moore::QueueType>(context.
convertType(*expr.type, loc));
560 Value contigElements;
562 for (
auto *operand : expr.operands()) {
563 bool isSingleElement =
568 if (!isSingleElement && contigElements) {
569 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
573 assert(!isLvalue &&
"checked by Slang");
574 auto value = convertLvalueOrRvalueExpression(*operand);
582 moore::RefType::get(context.
getContext(), queueType);
584 if (!contigElements) {
586 moore::VariableOp::create(builder, loc, queueRefType, {}, {});
588 moore::QueuePushBackOp::create(builder, loc, contigElements, value);
596 if (!(isa<moore::QueueType>(value.getType()) &&
597 cast<moore::QueueType>(value.getType()).getElementType() ==
603 operands.push_back(value);
606 if (contigElements) {
607 operands.push_back(moore::ReadOp::create(builder, loc, contigElements));
610 return moore::QueueConcatOp::create(builder, loc, queueType, operands);
614 Value visit(
const slang::ast::MemberAccessExpression &expr) {
619 auto *valueType = expr.value().type.get();
620 auto memberName = builder.getStringAttr(expr.member.name);
623 if (valueType->isStruct()) {
625 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
627 auto value = convertLvalueOrRvalueExpression(expr.value());
632 return moore::StructExtractRefOp::create(builder, loc, resultType,
634 return moore::StructExtractOp::create(builder, loc, resultType,
639 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
641 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
643 auto value = convertLvalueOrRvalueExpression(expr.value());
648 return moore::UnionExtractRefOp::create(builder, loc, resultType,
650 return moore::UnionExtractOp::create(builder, loc, type, memberName,
655 if (valueType->isClass()) {
659 auto targetTy = cast<moore::ClassHandleType>(valTy);
671 if (expr.member.kind != slang::ast::SymbolKind::Parameter) {
677 moore::ClassHandleType upcastTargetTy =
691 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(),
693 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
697 Value fieldRef = moore::ClassPropertyRefOp::create(
698 builder, loc, fieldRefTy, baseVal, fieldSym);
701 return isLvalue ? fieldRef
702 : moore::ReadOp::create(builder, loc, fieldRef);
705 slang::ConstantValue constVal;
706 if (
auto param = expr.member.as_if<slang::ast::ParameterSymbol>()) {
707 constVal = param->getValue();
712 mlir::emitError(loc) <<
"Parameter " << expr.member.name
713 <<
" has no constant value";
717 mlir::emitError(loc,
"expression of type ")
718 << valueType->toString() <<
" has no member fields";
730struct RvalueExprVisitor :
public ExprVisitor {
732 : ExprVisitor(
context, loc, false) {}
733 using ExprVisitor::visit;
736 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
737 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
738 auto lvalue =
context.lvalueStack.back();
739 return moore::ReadOp::create(builder, loc, lvalue);
743 Value visit(
const slang::ast::NamedValueExpression &expr) {
745 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
746 if (isa<moore::RefType>(value.getType())) {
747 auto readOp = moore::ReadOp::create(builder, loc, value);
748 if (
context.rvalueReadCallback)
749 context.rvalueReadCallback(readOp);
750 value = readOp.getResult();
756 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
757 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
758 return moore::ReadOp::create(builder, loc, value);
762 if (
auto *
const property =
763 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
765 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
769 auto constant =
context.evaluateConstant(expr);
770 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
775 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
776 d.attachNote(
context.convertLocation(expr.symbol.location))
777 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
782 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
783 auto hierLoc =
context.convertLocation(expr.symbol.location);
784 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
785 if (isa<moore::RefType>(value.getType())) {
786 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
787 if (
context.rvalueReadCallback)
788 context.rvalueReadCallback(readOp);
789 value = readOp.getResult();
796 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
797 << expr.symbol.name <<
"`";
798 d.attachNote(hierLoc) <<
"no rvalue generated for "
799 << slang::ast::toString(expr.symbol.kind);
804 Value visit(
const slang::ast::ConversionExpression &expr) {
805 auto type =
context.convertType(*expr.type);
808 return context.convertRvalueExpression(expr.operand(), type);
812 Value visit(
const slang::ast::AssignmentExpression &expr) {
813 auto lhs =
context.convertLvalueExpression(expr.left());
818 context.lvalueStack.push_back(lhs);
819 auto rhs =
context.convertRvalueExpression(
820 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
821 context.lvalueStack.pop_back();
828 if (!expr.isNonBlocking()) {
829 if (expr.timingControl)
830 if (failed(
context.convertTimingControl(*expr.timingControl)))
832 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
833 if (
context.variableAssignCallback)
834 context.variableAssignCallback(assignOp);
839 if (expr.timingControl) {
841 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
842 auto delay =
context.convertRvalueExpression(
843 ctrl->expr, moore::TimeType::get(builder.getContext()));
846 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
847 builder, loc, lhs, rhs, delay);
848 if (
context.variableAssignCallback)
849 context.variableAssignCallback(assignOp);
854 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
856 <<
"unsupported non-blocking assignment timing control: "
857 << slang::ast::toString(expr.timingControl->kind);
860 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
861 if (
context.variableAssignCallback)
862 context.variableAssignCallback(assignOp);
868 template <
class ConcreteOp>
869 Value createReduction(Value arg,
bool invert) {
870 arg =
context.convertToSimpleBitVector(arg);
873 Value result = ConcreteOp::create(builder, loc, arg);
875 result = moore::NotOp::create(builder, loc, result);
880 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
881 auto preValue = moore::ReadOp::create(builder, loc, arg);
887 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
890 auto one = moore::ConstantOp::create(
891 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
893 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
894 : moore::SubOp::create(builder, loc, preValue, one).getResult();
896 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
897 if (
context.variableAssignCallback)
898 context.variableAssignCallback(assignOp);
907 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
908 Value preValue = moore::ReadOp::create(builder, loc, arg);
911 bool isTime = isa<moore::TimeType>(preValue.getType());
913 preValue =
context.materializeConversion(
914 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
915 preValue,
false, loc);
917 moore::RealType realTy =
918 llvm::dyn_cast<moore::RealType>(preValue.getType());
923 if (realTy.getWidth() == moore::RealWidth::f32) {
924 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
925 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
927 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
929 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
932 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
936 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
937 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
940 postValue =
context.materializeConversion(
941 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
944 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
946 if (
context.variableAssignCallback)
947 context.variableAssignCallback(assignOp);
954 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
955 Type opFTy =
context.convertType(*expr.operand().type);
957 using slang::ast::UnaryOperator;
959 if (expr.op == UnaryOperator::Preincrement ||
960 expr.op == UnaryOperator::Predecrement ||
961 expr.op == UnaryOperator::Postincrement ||
962 expr.op == UnaryOperator::Postdecrement)
963 arg =
context.convertLvalueExpression(expr.operand());
965 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
970 if (isa<moore::TimeType>(arg.getType()))
971 arg =
context.materializeConversion(
972 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
977 case UnaryOperator::Plus:
979 case UnaryOperator::Minus:
980 return moore::NegRealOp::create(builder, loc, arg);
982 case UnaryOperator::Preincrement:
983 return createRealIncrement(arg,
true,
false);
984 case UnaryOperator::Predecrement:
985 return createRealIncrement(arg,
false,
false);
986 case UnaryOperator::Postincrement:
987 return createRealIncrement(arg,
true,
true);
988 case UnaryOperator::Postdecrement:
989 return createRealIncrement(arg,
false,
true);
991 case UnaryOperator::LogicalNot:
992 arg =
context.convertToBool(arg);
995 return moore::NotOp::create(builder, loc, arg);
998 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
999 <<
" not supported with real values!\n";
1005 Value visit(
const slang::ast::UnaryExpression &expr) {
1007 const auto *floatType =
1008 expr.operand().type->as_if<slang::ast::FloatingType>();
1011 return visitRealUOp(expr);
1013 using slang::ast::UnaryOperator;
1015 if (expr.op == UnaryOperator::Preincrement ||
1016 expr.op == UnaryOperator::Predecrement ||
1017 expr.op == UnaryOperator::Postincrement ||
1018 expr.op == UnaryOperator::Postdecrement)
1019 arg =
context.convertLvalueExpression(expr.operand());
1021 arg =
context.convertRvalueExpression(expr.operand());
1028 case UnaryOperator::Plus:
1029 return context.convertToSimpleBitVector(arg);
1031 case UnaryOperator::Minus:
1032 arg =
context.convertToSimpleBitVector(arg);
1035 return moore::NegOp::create(builder, loc, arg);
1037 case UnaryOperator::BitwiseNot:
1038 arg =
context.convertToSimpleBitVector(arg);
1041 return moore::NotOp::create(builder, loc, arg);
1043 case UnaryOperator::BitwiseAnd:
1044 return createReduction<moore::ReduceAndOp>(arg,
false);
1045 case UnaryOperator::BitwiseOr:
1046 return createReduction<moore::ReduceOrOp>(arg,
false);
1047 case UnaryOperator::BitwiseXor:
1048 return createReduction<moore::ReduceXorOp>(arg,
false);
1049 case UnaryOperator::BitwiseNand:
1050 return createReduction<moore::ReduceAndOp>(arg,
true);
1051 case UnaryOperator::BitwiseNor:
1052 return createReduction<moore::ReduceOrOp>(arg,
true);
1053 case UnaryOperator::BitwiseXnor:
1054 return createReduction<moore::ReduceXorOp>(arg,
true);
1056 case UnaryOperator::LogicalNot:
1057 arg =
context.convertToBool(arg);
1060 return moore::NotOp::create(builder, loc, arg);
1062 case UnaryOperator::Preincrement:
1063 return createIncrement(arg,
true,
false);
1064 case UnaryOperator::Predecrement:
1065 return createIncrement(arg,
false,
false);
1066 case UnaryOperator::Postincrement:
1067 return createIncrement(arg,
true,
true);
1068 case UnaryOperator::Postdecrement:
1069 return createIncrement(arg,
false,
true);
1072 mlir::emitError(loc,
"unsupported unary operator");
1077 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
1078 std::optional<Domain> domain = std::nullopt) {
1079 using slang::ast::BinaryOperator;
1083 lhs =
context.convertToBool(lhs, domain.value());
1084 rhs =
context.convertToBool(rhs, domain.value());
1086 lhs =
context.convertToBool(lhs);
1087 rhs =
context.convertToBool(rhs);
1094 case BinaryOperator::LogicalAnd:
1095 return moore::AndOp::create(builder, loc, lhs, rhs);
1097 case BinaryOperator::LogicalOr:
1098 return moore::OrOp::create(builder, loc, lhs, rhs);
1100 case BinaryOperator::LogicalImplication: {
1102 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1103 return moore::OrOp::create(builder, loc, notLHS, rhs);
1106 case BinaryOperator::LogicalEquivalence: {
1108 auto notLHS = moore::NotOp::create(builder, loc, lhs);
1109 auto notRHS = moore::NotOp::create(builder, loc, rhs);
1110 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
1111 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
1112 return moore::OrOp::create(builder, loc, both, notBoth);
1116 llvm_unreachable(
"not a logical BinaryOperator");
1120 Value visitHandleBOp(
const slang::ast::BinaryExpression &expr) {
1122 auto lhs =
context.convertRvalueExpression(expr.left());
1125 auto rhs =
context.convertRvalueExpression(expr.right());
1129 using slang::ast::BinaryOperator;
1132 case BinaryOperator::Equality:
1133 return moore::HandleEqOp::create(builder, loc, lhs, rhs);
1134 case BinaryOperator::Inequality:
1135 return moore::HandleNeOp::create(builder, loc, lhs, rhs);
1136 case BinaryOperator::CaseEquality:
1137 return moore::HandleCaseEqOp::create(builder, loc, lhs, rhs);
1138 case BinaryOperator::CaseInequality:
1139 return moore::HandleCaseNeOp::create(builder, loc, lhs, rhs);
1142 mlir::emitError(loc)
1143 <<
"Binary operator " << slang::ast::toString(expr.op)
1144 <<
" not supported with class handle valued operands!\n";
1149 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
1151 auto lhs =
context.convertRvalueExpression(expr.left());
1154 auto rhs =
context.convertRvalueExpression(expr.right());
1158 if (isa<moore::TimeType>(lhs.getType()) ||
1159 isa<moore::TimeType>(rhs.getType())) {
1160 lhs =
context.materializeConversion(
1161 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1163 rhs =
context.materializeConversion(
1164 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1168 using slang::ast::BinaryOperator;
1170 case BinaryOperator::Add:
1171 return moore::AddRealOp::create(builder, loc, lhs, rhs);
1172 case BinaryOperator::Subtract:
1173 return moore::SubRealOp::create(builder, loc, lhs, rhs);
1174 case BinaryOperator::Multiply:
1175 return moore::MulRealOp::create(builder, loc, lhs, rhs);
1176 case BinaryOperator::Divide:
1177 return moore::DivRealOp::create(builder, loc, lhs, rhs);
1178 case BinaryOperator::Power:
1179 return moore::PowRealOp::create(builder, loc, lhs, rhs);
1181 case BinaryOperator::Equality:
1182 return moore::EqRealOp::create(builder, loc, lhs, rhs);
1183 case BinaryOperator::Inequality:
1184 return moore::NeRealOp::create(builder, loc, lhs, rhs);
1186 case BinaryOperator::GreaterThan:
1187 return moore::FgtOp::create(builder, loc, lhs, rhs);
1188 case BinaryOperator::LessThan:
1189 return moore::FltOp::create(builder, loc, lhs, rhs);
1190 case BinaryOperator::GreaterThanEqual:
1191 return moore::FgeOp::create(builder, loc, lhs, rhs);
1192 case BinaryOperator::LessThanEqual:
1193 return moore::FleOp::create(builder, loc, lhs, rhs);
1195 case BinaryOperator::LogicalAnd:
1196 case BinaryOperator::LogicalOr:
1197 case BinaryOperator::LogicalImplication:
1198 case BinaryOperator::LogicalEquivalence:
1199 return buildLogicalBOp(expr.op, lhs, rhs);
1202 mlir::emitError(loc) <<
"Binary operator "
1203 << slang::ast::toString(expr.op)
1204 <<
" not supported with real valued operands!\n";
1211 template <
class ConcreteOp>
1212 Value createBinary(Value lhs, Value rhs) {
1213 lhs =
context.convertToSimpleBitVector(lhs);
1216 rhs =
context.convertToSimpleBitVector(rhs);
1219 return ConcreteOp::create(builder, loc, lhs, rhs);
1223 Value visit(
const slang::ast::BinaryExpression &expr) {
1225 const auto *rhsFloatType =
1226 expr.right().type->as_if<slang::ast::FloatingType>();
1227 const auto *lhsFloatType =
1228 expr.left().type->as_if<slang::ast::FloatingType>();
1231 if (rhsFloatType || lhsFloatType)
1232 return visitRealBOp(expr);
1235 const auto rhsIsClass = expr.right().type->isClass();
1236 const auto lhsIsClass = expr.left().type->isClass();
1237 const auto rhsIsChandle = expr.right().type->isCHandle();
1238 const auto lhsIsChandle = expr.left().type->isCHandle();
1240 if (rhsIsClass || lhsIsClass || rhsIsChandle || lhsIsChandle)
1241 return visitHandleBOp(expr);
1243 auto lhs =
context.convertRvalueExpression(expr.left());
1246 auto rhs =
context.convertRvalueExpression(expr.right());
1251 Domain domain = Domain::TwoValued;
1252 if (expr.type->isFourState() || expr.left().type->isFourState() ||
1253 expr.right().type->isFourState())
1254 domain = Domain::FourValued;
1256 using slang::ast::BinaryOperator;
1258 case BinaryOperator::Add:
1259 return createBinary<moore::AddOp>(lhs, rhs);
1260 case BinaryOperator::Subtract:
1261 return createBinary<moore::SubOp>(lhs, rhs);
1262 case BinaryOperator::Multiply:
1263 return createBinary<moore::MulOp>(lhs, rhs);
1264 case BinaryOperator::Divide:
1265 if (expr.type->isSigned())
1266 return createBinary<moore::DivSOp>(lhs, rhs);
1268 return createBinary<moore::DivUOp>(lhs, rhs);
1269 case BinaryOperator::Mod:
1270 if (expr.type->isSigned())
1271 return createBinary<moore::ModSOp>(lhs, rhs);
1273 return createBinary<moore::ModUOp>(lhs, rhs);
1274 case BinaryOperator::Power: {
1279 auto rhsCast =
context.materializeConversion(
1280 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
1281 if (expr.type->isSigned())
1282 return createBinary<moore::PowSOp>(lhs, rhsCast);
1284 return createBinary<moore::PowUOp>(lhs, rhsCast);
1287 case BinaryOperator::BinaryAnd:
1288 return createBinary<moore::AndOp>(lhs, rhs);
1289 case BinaryOperator::BinaryOr:
1290 return createBinary<moore::OrOp>(lhs, rhs);
1291 case BinaryOperator::BinaryXor:
1292 return createBinary<moore::XorOp>(lhs, rhs);
1293 case BinaryOperator::BinaryXnor: {
1294 auto result = createBinary<moore::XorOp>(lhs, rhs);
1297 return moore::NotOp::create(builder, loc, result);
1300 case BinaryOperator::Equality:
1301 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1302 return moore::UArrayCmpOp::create(
1303 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1304 else if (isa<moore::StringType>(lhs.getType()))
1305 return moore::StringCmpOp::create(
1306 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
1307 else if (isa<moore::QueueType>(lhs.getType()))
1308 return moore::QueueCmpOp::create(
1309 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1311 return createBinary<moore::EqOp>(lhs, rhs);
1312 case BinaryOperator::Inequality:
1313 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1314 return moore::UArrayCmpOp::create(
1315 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1316 else if (isa<moore::StringType>(lhs.getType()))
1317 return moore::StringCmpOp::create(
1318 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1319 else if (isa<moore::QueueType>(lhs.getType()))
1320 return moore::QueueCmpOp::create(
1321 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1323 return createBinary<moore::NeOp>(lhs, rhs);
1324 case BinaryOperator::CaseEquality:
1325 return createBinary<moore::CaseEqOp>(lhs, rhs);
1326 case BinaryOperator::CaseInequality:
1327 return createBinary<moore::CaseNeOp>(lhs, rhs);
1328 case BinaryOperator::WildcardEquality:
1329 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1330 case BinaryOperator::WildcardInequality:
1331 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1333 case BinaryOperator::GreaterThanEqual:
1334 if (expr.left().type->isSigned())
1335 return createBinary<moore::SgeOp>(lhs, rhs);
1336 else if (isa<moore::StringType>(lhs.getType()))
1337 return moore::StringCmpOp::create(
1338 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1340 return createBinary<moore::UgeOp>(lhs, rhs);
1341 case BinaryOperator::GreaterThan:
1342 if (expr.left().type->isSigned())
1343 return createBinary<moore::SgtOp>(lhs, rhs);
1344 else if (isa<moore::StringType>(lhs.getType()))
1345 return moore::StringCmpOp::create(
1346 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1348 return createBinary<moore::UgtOp>(lhs, rhs);
1349 case BinaryOperator::LessThanEqual:
1350 if (expr.left().type->isSigned())
1351 return createBinary<moore::SleOp>(lhs, rhs);
1352 else if (isa<moore::StringType>(lhs.getType()))
1353 return moore::StringCmpOp::create(
1354 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1356 return createBinary<moore::UleOp>(lhs, rhs);
1357 case BinaryOperator::LessThan:
1358 if (expr.left().type->isSigned())
1359 return createBinary<moore::SltOp>(lhs, rhs);
1360 else if (isa<moore::StringType>(lhs.getType()))
1361 return moore::StringCmpOp::create(
1362 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1364 return createBinary<moore::UltOp>(lhs, rhs);
1366 case BinaryOperator::LogicalAnd:
1367 case BinaryOperator::LogicalOr:
1368 case BinaryOperator::LogicalImplication:
1369 case BinaryOperator::LogicalEquivalence:
1370 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1372 case BinaryOperator::LogicalShiftLeft:
1373 return createBinary<moore::ShlOp>(lhs, rhs);
1374 case BinaryOperator::LogicalShiftRight:
1375 return createBinary<moore::ShrOp>(lhs, rhs);
1376 case BinaryOperator::ArithmeticShiftLeft:
1377 return createBinary<moore::ShlOp>(lhs, rhs);
1378 case BinaryOperator::ArithmeticShiftRight: {
1381 lhs =
context.convertToSimpleBitVector(lhs);
1382 rhs =
context.convertToSimpleBitVector(rhs);
1385 if (expr.type->isSigned())
1386 return moore::AShrOp::create(builder, loc, lhs, rhs);
1387 return moore::ShrOp::create(builder, loc, lhs, rhs);
1391 mlir::emitError(loc,
"unsupported binary operator");
1396 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1397 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1401 Value visit(
const slang::ast::IntegerLiteral &expr) {
1402 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1406 Value visit(
const slang::ast::TimeLiteral &expr) {
1411 double value = std::round(expr.getValue() * scale);
1421 static constexpr uint64_t limit =
1422 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1423 if (value > limit) {
1424 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1428 return moore::ConstantTimeOp::create(builder, loc,
1429 static_cast<uint64_t
>(value));
1433 Value visit(
const slang::ast::ReplicationExpression &expr) {
1434 auto type =
context.convertType(*expr.type);
1435 auto value =
context.convertRvalueExpression(expr.concat());
1438 return moore::ReplicateOp::create(builder, loc, type, value);
1442 Value visit(
const slang::ast::InsideExpression &expr) {
1443 auto lhs =
context.convertToSimpleBitVector(
1444 context.convertRvalueExpression(expr.left()));
1448 SmallVector<Value> conditions;
1451 for (
const auto *listExpr : expr.rangeList()) {
1455 if (
const auto *openRange =
1456 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
1458 auto lowBound =
context.convertToSimpleBitVector(
1459 context.convertRvalueExpression(openRange->left()));
1460 auto highBound =
context.convertToSimpleBitVector(
1461 context.convertRvalueExpression(openRange->right()));
1462 if (!lowBound || !highBound)
1464 Value leftValue, rightValue;
1467 if (openRange->left().type->isSigned() ||
1468 expr.left().type->isSigned()) {
1469 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
1471 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
1473 if (openRange->right().type->isSigned() ||
1474 expr.left().type->isSigned()) {
1475 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
1477 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
1479 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
1482 if (!listExpr->type->isIntegral()) {
1483 if (listExpr->type->isUnpackedArray()) {
1485 loc,
"unpacked arrays in 'inside' expressions not supported");
1489 loc,
"only simple bit vectors supported in 'inside' expressions");
1493 auto value =
context.convertToSimpleBitVector(
1494 context.convertRvalueExpression(*listExpr));
1497 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
1499 conditions.push_back(cond);
1503 auto result = conditions.back();
1504 conditions.pop_back();
1505 while (!conditions.empty()) {
1506 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1507 conditions.pop_back();
1513 Value visit(
const slang::ast::ConditionalExpression &expr) {
1514 auto type =
context.convertType(*expr.type);
1517 if (expr.conditions.size() > 1) {
1518 mlir::emitError(loc)
1519 <<
"unsupported conditional expression with more than one condition";
1522 const auto &cond = expr.conditions[0];
1524 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1528 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1531 auto conditionalOp =
1532 moore::ConditionalOp::create(builder, loc, type, value);
1535 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1536 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1538 OpBuilder::InsertionGuard g(builder);
1541 builder.setInsertionPointToStart(&trueBlock);
1542 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1545 moore::YieldOp::create(builder, loc, trueValue);
1548 builder.setInsertionPointToStart(&falseBlock);
1549 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1552 moore::YieldOp::create(builder, loc, falseValue);
1554 return conditionalOp.getResult();
1558 Value visit(
const slang::ast::CallExpression &expr) {
1560 auto constant =
context.evaluateConstant(expr);
1561 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1565 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1571 std::pair<Value, moore::ClassHandleType>
1572 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1574 moore::ClassHandleType handleTy;
1578 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1579 thisRef =
context.convertRvalueExpression(*recvExpr);
1584 thisRef =
context.getImplicitThisRef();
1586 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1587 <<
"' called without an object";
1591 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1592 return {thisRef, handleTy};
1596 mlir::CallOpInterface
1597 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1599 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1600 SmallVector<Value> &arguments,
1601 SmallVector<Type> &resultTypes) {
1604 auto funcTy = lowering->
op.getFunctionType();
1605 auto expected0 = funcTy.getInput(0);
1606 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1609 auto implicitThisRef =
context.materializeConversion(
1610 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1613 SmallVector<Value> explicitArguments;
1614 explicitArguments.reserve(arguments.size() + 1);
1615 explicitArguments.push_back(implicitThisRef);
1616 explicitArguments.append(arguments.begin(), arguments.end());
1619 const bool isVirtual =
1620 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1623 auto calleeSym = lowering->
op.getSymName();
1625 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1629 auto funcName = subroutine->name;
1630 auto method = moore::VTableLoadMethodOp::create(
1631 builder, loc, funcTy, actualThisRef,
1632 SymbolRefAttr::get(
context.getContext(), funcName));
1633 return mlir::func::CallIndirectOp::create(builder, loc, method,
1638 Value visitCall(
const slang::ast::CallExpression &expr,
1639 const slang::ast::SubroutineSymbol *subroutine) {
1641 const bool isMethod = (subroutine->thisVar !=
nullptr);
1643 auto *lowering =
context.declareFunction(*subroutine);
1646 auto convertedFunction =
context.convertFunction(*subroutine);
1647 if (failed(convertedFunction))
1653 SmallVector<Value> arguments;
1654 for (
auto [callArg, declArg] :
1655 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1659 auto *expr = callArg;
1660 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1661 expr = &assign->left();
1664 auto type =
context.convertType(declArg->getType());
1665 if (declArg->direction == slang::ast::ArgumentDirection::In) {
1666 value =
context.convertRvalueExpression(*expr, type);
1668 Value lvalue =
context.convertLvalueExpression(*expr);
1669 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
1673 context.materializeConversion(moore::RefType::get(unpackedType),
1674 lvalue, expr->type->isSigned(), loc);
1678 arguments.push_back(value);
1682 auto materializeCaptureAtCall = [&](Value cap) -> Value {
1684 auto refTy = dyn_cast<moore::RefType>(cap.getType());
1686 lowering->
op.emitError(
1687 "expected captured value to be moore::RefType");
1694 Region *capRegion = [&]() -> Region * {
1695 if (
auto ba = dyn_cast<BlockArgument>(cap))
1696 return ba.getOwner()->getParent();
1697 if (
auto *def = cap.getDefiningOp())
1698 return def->getParentRegion();
1702 Region *callRegion =
1703 builder.getBlock() ? builder.getBlock()->getParent() :
nullptr;
1705 for (Region *r = callRegion; r; r = r->getParentRegion()) {
1706 if (r == capRegion) {
1713 lowering->
op.emitError()
1714 <<
"cannot materialize captured ref at call site; non-symbol "
1716 << (cap.getDefiningOp()
1717 ? cap.getDefiningOp()->getName().getStringRef()
1722 for (Value cap : lowering->captures) {
1723 Value mat = materializeCaptureAtCall(cap);
1726 arguments.push_back(mat);
1731 SmallVector<Type> resultTypes(
1732 lowering->
op.getFunctionType().getResults().begin(),
1733 lowering->
op.getFunctionType().getResults().end());
1735 mlir::CallOpInterface callOp;
1739 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1740 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1741 arguments, resultTypes);
1745 mlir::func::CallOp::create(builder, loc, lowering->
op, arguments);
1748 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1752 if (resultTypes.size() == 0)
1753 return mlir::UnrealizedConversionCastOp::create(
1754 builder, loc, moore::VoidType::get(
context.getContext()),
1762 Value visitCall(
const slang::ast::CallExpression &expr,
1763 const slang::ast::CallExpression::SystemCallInfo &info) {
1764 const auto &subroutine = *
info.subroutine;
1769 bool isAssertionCall = llvm::StringSwitch<bool>(subroutine.name)
1770 .Cases({
"$rose",
"$fell",
"$stable",
"$changed",
1771 "$past",
"$sampled"},
1775 if (isAssertionCall)
1776 return context.convertAssertionCallExpression(expr, info, loc);
1778 auto args = expr.arguments();
1780 FailureOr<Value> result = Value{};
1790 if (!subroutine.name.compare(
"$sformatf")) {
1792 auto fmtValue =
context.convertFormatString(
1793 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1794 if (failed(fmtValue))
1796 return fmtValue.value();
1801 bool isByRefOp = args.size() >= 1 &&
1802 ((args[0]->type->isQueue() && subroutine.name !=
"size") ||
1803 args[0]->type->isAssociativeArray());
1811 switch (args.size()) {
1813 result =
context.convertSystemCallArity0(subroutine, loc);
1817 value = isByRefOp ?
context.convertLvalueExpression(*args[0])
1818 :
context.convertRvalueExpression(*args[0]);
1821 result =
context.convertSystemCallArity1(subroutine, loc, value);
1825 value = isByRefOp ?
context.convertLvalueExpression(*args[0])
1826 :
context.convertRvalueExpression(*args[0]);
1827 value2 =
context.convertRvalueExpression(*args[1]);
1828 if (!value || !value2)
1830 result =
context.convertSystemCallArity2(subroutine, loc, value, value2);
1846 auto ty =
context.convertType(*expr.type);
1847 return context.materializeConversion(ty, *result, expr.type->isSigned(),
1852 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
1858 Value visit(
const slang::ast::StringLiteral &expr) {
1859 auto type =
context.convertType(*expr.type);
1860 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1864 Value visit(
const slang::ast::RealLiteral &expr) {
1865 auto fTy = mlir::Float64Type::get(
context.getContext());
1866 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
1867 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
1872 FailureOr<SmallVector<Value>>
1873 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1874 std::variant<Type, ArrayRef<Type>> expectedTypes,
1875 unsigned replCount) {
1876 const auto &elts = expr.elements();
1877 const size_t elementCount = elts.size();
1880 const bool hasBroadcast =
1881 std::holds_alternative<Type>(expectedTypes) &&
1882 static_cast<bool>(std::get<Type>(expectedTypes));
1884 const bool hasPerElem =
1885 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1886 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1890 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1891 if (types.size() != elementCount) {
1892 mlir::emitError(loc)
1893 <<
"assignment pattern arity mismatch: expected " << types.size()
1894 <<
" elements, got " << elementCount;
1899 SmallVector<Value> converted;
1900 converted.reserve(elementCount * std::max(1u, replCount));
1903 if (!hasBroadcast && !hasPerElem) {
1905 for (
const auto *elementExpr : elts) {
1906 Value v =
context.convertRvalueExpression(*elementExpr);
1909 converted.push_back(v);
1911 }
else if (hasBroadcast) {
1913 Type want = std::get<Type>(expectedTypes);
1914 for (
const auto *elementExpr : elts) {
1915 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1916 :
context.convertRvalueExpression(*elementExpr);
1919 converted.push_back(v);
1922 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1923 for (
size_t i = 0; i < elementCount; ++i) {
1924 Type want = types[i];
1925 const auto *elementExpr = elts[i];
1926 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1927 :
context.convertRvalueExpression(*elementExpr);
1930 converted.push_back(v);
1934 for (
unsigned i = 1; i < replCount; ++i)
1935 converted.append(converted.begin(), converted.begin() + elementCount);
1941 Value visitAssignmentPattern(
1942 const slang::ast::AssignmentPatternExpressionBase &expr,
1943 unsigned replCount = 1) {
1944 auto type =
context.convertType(*expr.type);
1945 const auto &elts = expr.elements();
1948 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1949 auto elements = convertElements(expr, {}, replCount);
1951 if (failed(elements))
1954 assert(intType.getWidth() == elements->size());
1955 std::reverse(elements->begin(), elements->end());
1956 return moore::ConcatOp::create(builder, loc, intType, *elements);
1960 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1961 SmallVector<Type> expectedTy;
1962 expectedTy.reserve(structType.getMembers().size());
1963 for (
auto member : structType.getMembers())
1964 expectedTy.push_back(member.type);
1966 FailureOr<SmallVector<Value>> elements;
1967 if (expectedTy.size() == elts.size())
1968 elements = convertElements(expr, expectedTy, replCount);
1970 elements = convertElements(expr, {}, replCount);
1972 if (failed(elements))
1975 assert(structType.getMembers().size() == elements->size());
1976 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1980 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1981 SmallVector<Type> expectedTy;
1982 expectedTy.reserve(structType.getMembers().size());
1983 for (
auto member : structType.getMembers())
1984 expectedTy.push_back(member.type);
1986 FailureOr<SmallVector<Value>> elements;
1987 if (expectedTy.size() == elts.size())
1988 elements = convertElements(expr, expectedTy, replCount);
1990 elements = convertElements(expr, {}, replCount);
1992 if (failed(elements))
1995 assert(structType.getMembers().size() == elements->size());
1997 return moore::StructCreateOp::create(builder, loc, structType, *elements);
2001 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
2003 convertElements(expr, arrayType.getElementType(), replCount);
2005 if (failed(elements))
2008 assert(arrayType.getSize() == elements->size());
2009 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2013 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
2015 convertElements(expr, arrayType.getElementType(), replCount);
2017 if (failed(elements))
2020 assert(arrayType.getSize() == elements->size());
2021 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
2024 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
2028 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
2029 return visitAssignmentPattern(expr);
2032 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
2033 return visitAssignmentPattern(expr);
2036 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
2038 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
2039 assert(count &&
"Slang guarantees constant non-zero replication count");
2040 return visitAssignmentPattern(expr, *count);
2043 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2044 SmallVector<Value> operands;
2045 for (
auto stream : expr.streams()) {
2046 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2047 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2048 mlir::emitError(operandLoc)
2049 <<
"Moore only support streaming "
2050 "concatenation with fixed size 'with expression'";
2054 if (stream.constantWithWidth.has_value()) {
2055 value =
context.convertRvalueExpression(*stream.withExpr);
2056 auto type = cast<moore::UnpackedType>(value.getType());
2057 auto intType = moore::IntType::get(
2058 context.getContext(), type.getBitSize().value(), type.getDomain());
2060 value =
context.materializeConversion(intType, value,
false, loc);
2062 value =
context.convertRvalueExpression(*stream.operand);
2065 value =
context.convertToSimpleBitVector(value);
2068 operands.push_back(value);
2072 if (operands.size() == 1) {
2075 value = operands.front();
2077 value = moore::ConcatOp::create(builder, loc, operands).getResult();
2080 if (expr.getSliceSize() == 0) {
2084 auto type = cast<moore::IntType>(value.getType());
2085 SmallVector<Value> slicedOperands;
2086 auto iterMax = type.getWidth() / expr.getSliceSize();
2087 auto remainSize = type.getWidth() % expr.getSliceSize();
2089 for (
size_t i = 0; i < iterMax; i++) {
2090 auto extractResultType = moore::IntType::get(
2091 context.getContext(), expr.getSliceSize(), type.getDomain());
2093 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
2094 value, i * expr.getSliceSize());
2095 slicedOperands.push_back(extracted);
2099 auto extractResultType = moore::IntType::get(
2100 context.getContext(), remainSize, type.getDomain());
2103 moore::ExtractOp::create(builder, loc, extractResultType, value,
2104 iterMax * expr.getSliceSize());
2105 slicedOperands.push_back(extracted);
2108 return moore::ConcatOp::create(builder, loc, slicedOperands);
2111 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
2112 return context.convertAssertionExpression(expr.body, loc);
2115 Value visit(
const slang::ast::UnboundedLiteral &expr) {
2117 "slang checks $ only used within queue index expression");
2121 moore::QueueSizeBIOp::create(builder, loc,
context.getIndexedQueue());
2122 auto one = moore::ConstantOp::create(builder, loc, queueSize.getType(), 1);
2123 auto lastElement = moore::SubOp::create(builder, loc, queueSize, one);
2140 Value visit(
const slang::ast::NewClassExpression &expr) {
2141 auto type =
context.convertType(*expr.type);
2142 auto classTy = dyn_cast<moore::ClassHandleType>(type);
2148 if (!classTy && expr.isSuperClass) {
2149 newObj =
context.getImplicitThisRef();
2150 if (!newObj || !newObj.getType() ||
2151 !isa<moore::ClassHandleType>(newObj.getType())) {
2152 mlir::emitError(loc) <<
"implicit this ref was not set while "
2153 "converting new class function";
2156 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
2158 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
2159 context.intoModuleOp, thisType.getClassSym()));
2160 auto baseClassSym = classDecl.getBase();
2161 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
2162 baseClassSym.value());
2165 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
2168 const auto *constructor = expr.constructorCall();
2173 if (
const auto *callConstructor =
2174 constructor->as_if<slang::ast::CallExpression>())
2175 if (
const auto *subroutine =
2176 std::get_if<const slang::ast::SubroutineSymbol *>(
2177 &callConstructor->subroutine)) {
2180 if (!(*subroutine)->thisVar) {
2181 mlir::emitError(loc) <<
"Expected subroutine called by new to use an "
2182 "implicit this reference";
2185 if (failed(
context.convertFunction(**subroutine)))
2188 auto savedThis =
context.currentThisRef;
2189 context.currentThisRef = newObj;
2190 llvm::scope_exit restoreThis(
2191 [&] {
context.currentThisRef = savedThis; });
2193 if (!visitCall(*callConstructor, *subroutine))
2202 template <
typename T>
2203 Value visit(T &&node) {
2204 mlir::emitError(loc,
"unsupported expression: ")
2205 << slang::ast::toString(node.kind);
2209 Value visitInvalid(
const slang::ast::Expression &expr) {
2210 mlir::emitError(loc,
"invalid expression");
2221struct LvalueExprVisitor :
public ExprVisitor {
2223 : ExprVisitor(
context, loc, true) {}
2224 using ExprVisitor::visit;
2227 Value visit(
const slang::ast::NamedValueExpression &expr) {
2229 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2233 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2234 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2236 if (
auto *
const property =
2237 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
2241 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
2242 d.attachNote(
context.convertLocation(expr.symbol.location))
2243 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2248 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
2250 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2254 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2255 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2259 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
2260 << expr.symbol.name <<
"`";
2261 d.attachNote(
context.convertLocation(expr.symbol.location))
2262 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2266 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2267 SmallVector<Value> operands;
2268 for (
auto stream : expr.streams()) {
2269 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2270 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2271 mlir::emitError(operandLoc)
2272 <<
"Moore only support streaming "
2273 "concatenation with fixed size 'with expression'";
2277 if (stream.constantWithWidth.has_value()) {
2278 value =
context.convertLvalueExpression(*stream.withExpr);
2279 auto type = cast<moore::UnpackedType>(
2280 cast<moore::RefType>(value.getType()).getNestedType());
2281 auto intType = moore::RefType::get(moore::IntType::get(
2282 context.getContext(), type.getBitSize().value(), type.getDomain()));
2284 value =
context.materializeConversion(intType, value,
false, loc);
2286 value =
context.convertLvalueExpression(*stream.operand);
2291 operands.push_back(value);
2294 if (operands.size() == 1) {
2297 value = operands.front();
2299 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
2302 if (expr.getSliceSize() == 0) {
2306 auto type = cast<moore::IntType>(
2307 cast<moore::RefType>(value.getType()).getNestedType());
2308 SmallVector<Value> slicedOperands;
2309 auto widthSum = type.getWidth();
2310 auto domain = type.getDomain();
2311 auto iterMax = widthSum / expr.getSliceSize();
2312 auto remainSize = widthSum % expr.getSliceSize();
2314 for (
size_t i = 0; i < iterMax; i++) {
2315 auto extractResultType = moore::RefType::get(moore::IntType::get(
2316 context.getContext(), expr.getSliceSize(), domain));
2318 auto extracted = moore::ExtractRefOp::create(
2319 builder, loc, extractResultType, value, i * expr.getSliceSize());
2320 slicedOperands.push_back(extracted);
2324 auto extractResultType = moore::RefType::get(
2325 moore::IntType::get(
context.getContext(), remainSize, domain));
2328 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
2329 iterMax * expr.getSliceSize());
2330 slicedOperands.push_back(extracted);
2333 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
2337 template <
typename T>
2338 Value visit(T &&node) {
2339 return context.convertRvalueExpression(node);
2342 Value visitInvalid(
const slang::ast::Expression &expr) {
2343 mlir::emitError(loc,
"invalid expression");
2353Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
2354 Type requiredType) {
2356 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2357 if (value && requiredType)
2365 return expr.visit(LvalueExprVisitor(*
this, loc));
2373 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2374 if (type.getBitSize() == 1)
2376 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2377 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2378 mlir::emitError(value.getLoc(),
"expression of type ")
2379 << value.getType() <<
" cannot be cast to a boolean";
2385 const slang::ast::Type &astType,
2387 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2391 if (svreal.isShortReal() &&
2392 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2393 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2394 }
else if (svreal.isReal() &&
2395 floatType->floatKind == slang::ast::FloatingType::Real) {
2396 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2398 mlir::emitError(loc) <<
"invalid real constant";
2402 return moore::ConstantRealOp::create(
builder, loc, attr);
2407 const slang::ast::Type &astType,
2409 slang::ConstantValue intVal = stringLiteral.convertToInt();
2410 auto effectiveWidth = intVal.getEffectiveWidth();
2411 if (!effectiveWidth)
2414 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2416 if (astType.isString()) {
2417 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2418 stringLiteral.toString())
2420 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2427 const slang::ast::Type &astType, Location loc) {
2432 bool typeIsFourValued =
false;
2433 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2437 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2438 fvint.hasUnknown() || typeIsFourValued
2441 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2446 const slang::ConstantValue &constant,
2447 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2455 if (astType.elementType.isIntegral())
2456 bitWidth = astType.elementType.getBitWidth();
2460 bool typeIsFourValued =
false;
2463 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2474 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2476 auto arrType = moore::UnpackedArrayType::get(
2477 getContext(), constant.elements().size(), intType);
2479 llvm::SmallVector<mlir::Value> elemVals;
2480 moore::ConstantOp constOp;
2482 mlir::OpBuilder::InsertionGuard guard(
builder);
2485 for (
auto elem : constant.elements()) {
2487 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2488 elemVals.push_back(constOp.getResult());
2493 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2495 return arrayOp.getResult();
2499 const slang::ast::Type &type, Location loc) {
2501 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2503 if (constant.isInteger())
2505 if (constant.isReal() || constant.isShortReal())
2507 if (constant.isString())
2515 using slang::ast::EvalFlags;
2516 slang::ast::EvalContext evalContext(
2518 slang::ast::LookupLocation::max),
2519 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2520 return expr.eval(evalContext);
2529 auto type = moore::IntType::get(
getContext(), 1, domain);
2536 if (isa<moore::IntType>(value.getType()))
2543 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2544 if (
auto sbvType = packed.getSimpleBitVector())
2547 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2548 <<
" cannot be cast to a simple bit vector";
2557 if (isa<moore::IntType>(value.getType()))
2560 auto &builder =
context.builder;
2561 auto packedType = cast<moore::PackedType>(value.getType());
2562 auto intType = packedType.getSimpleBitVector();
2567 if (isa<moore::TimeType>(packedType) &&
2569 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2570 auto scale = moore::ConstantOp::create(builder, loc, intType,
2572 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2578 if (packedType.containsTimeType()) {
2579 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2580 <<
" cannot be converted to " << intType
2581 <<
"; contains a time type";
2586 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2594 Value value, Location loc) {
2595 if (value.getType() == packedType)
2598 auto &builder =
context.builder;
2599 auto intType = cast<moore::IntType>(value.getType());
2604 if (isa<moore::TimeType>(packedType) &&
2606 auto scale = moore::ConstantOp::create(builder, loc, intType,
2608 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2609 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2616 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2617 <<
" cannot be converted to " << packedType
2618 <<
"; contains a time type";
2623 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2629 moore::ClassHandleType expectedHandleTy) {
2630 auto loc = actualHandle.getLoc();
2632 auto actualTy = actualHandle.getType();
2633 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2634 if (!actualHandleTy) {
2635 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2641 if (actualHandleTy == expectedHandleTy)
2642 return actualHandle;
2644 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
2645 mlir::emitError(loc)
2646 <<
"receiver class " << actualHandleTy.getClassSym()
2647 <<
" is not the same as, or derived from, expected base class "
2648 << expectedHandleTy.getClassSym().getRootReference();
2653 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
2654 expectedHandleTy, actualHandle)
2662 if (type == value.getType())
2667 auto dstPacked = dyn_cast<moore::PackedType>(type);
2668 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2669 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2670 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2672 if (dstInt && srcInt) {
2680 auto resizedType = moore::IntType::get(
2681 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2682 if (dstInt.getWidth() < srcInt.getWidth()) {
2683 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2684 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2686 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2688 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2692 if (dstInt.getDomain() != srcInt.getDomain()) {
2694 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2696 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2704 assert(value.getType() == type);
2709 if (isa<moore::StringType>(type) &&
2710 isa<moore::FormatStringType>(value.getType())) {
2711 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2715 if (isa<moore::FormatStringType>(type) &&
2716 isa<moore::StringType>(value.getType())) {
2717 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2722 if (isa<moore::QueueType>(type) && isa<moore::QueueType>(value.getType()) &&
2723 cast<moore::QueueType>(type).getElementType() ==
2724 cast<moore::QueueType>(value.getType()).getElementType())
2725 return builder.createOrFold<moore::QueueResizeOp>(loc, type, value);
2728 if (isa<moore::QueueType>(type) &&
2729 isa<moore::UnpackedArrayType>(value.getType())) {
2730 auto queueElType = dyn_cast<moore::QueueType>(type).getElementType();
2731 auto unpackedArrayElType =
2732 dyn_cast<moore::UnpackedArrayType>(value.getType()).getElementType();
2734 if (queueElType == unpackedArrayElType) {
2735 return builder.createOrFold<moore::QueueFromUnpackedArrayOp>(loc, type,
2741 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2742 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2743 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2751 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2754 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2759 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2763 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
2764 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
2767 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
2769 return mlir::Float32Type::get(
builder.getContext());
2771 return mlir::Float64Type::get(
builder.getContext());
2775 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
2777 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
2779 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
2780 auto scale = moore::ConstantRealOp::create(
2781 builder, loc, value.getType(),
2783 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
2784 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
2785 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
2786 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
2790 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
2791 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
2792 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
2793 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
2794 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
2795 auto scale = moore::ConstantRealOp::create(
2798 return moore::DivRealOp::create(
builder, loc, asReal, scale);
2802 if (isa<moore::StringType>(type)) {
2803 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
2805 value = moore::LogicToIntOp::create(
builder, loc, value);
2806 return moore::IntToStringOp::create(
builder, loc, value);
2811 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2812 if (isa<moore::StringType>(value.getType())) {
2813 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
2817 return moore::IntToLogicOp::create(
builder, loc, value);
2824 if (isa<moore::FormatStringType>(type)) {
2826 value, isSigned, loc);
2829 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
2832 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
2833 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
2835 if (isa<moore::ClassHandleType>(type) &&
2836 isa<moore::ClassHandleType>(value.getType()))
2840 if (value.getType() != type)
2841 value = moore::ConversionOp::create(
builder, loc, type, value);
2849 auto systemCallRes =
2850 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2853 return moore::UrandomBIOp::create(
builder, loc,
nullptr);
2857 return moore::RandomBIOp::create(
builder, loc,
nullptr);
2861 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2864 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2867 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2868 .Default([&]() -> Value {
return {}; });
2869 return systemCallRes();
2874 Location loc, Value value) {
2875 auto systemCallRes =
2876 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2878 .Case(
"$signed", [&]() {
return value; })
2879 .Case(
"$unsigned", [&]() {
return value; })
2883 [&]() -> FailureOr<Value> {
2887 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
2891 return moore::LnBIOp::create(
builder, loc, value);
2895 return moore::Log10BIOp::create(
builder, loc, value);
2899 return moore::SinBIOp::create(
builder, loc, value);
2903 return moore::CosBIOp::create(
builder, loc, value);
2907 return moore::TanBIOp::create(
builder, loc, value);
2911 return moore::ExpBIOp::create(
builder, loc, value);
2915 return moore::SqrtBIOp::create(
builder, loc, value);
2919 return moore::FloorBIOp::create(
builder, loc, value);
2923 return moore::CeilBIOp::create(
builder, loc, value);
2927 return moore::AsinBIOp::create(
builder, loc, value);
2931 return moore::AcosBIOp::create(
builder, loc, value);
2935 return moore::AtanBIOp::create(
builder, loc, value);
2939 return moore::SinhBIOp::create(
builder, loc, value);
2943 return moore::CoshBIOp::create(
builder, loc, value);
2947 return moore::TanhBIOp::create(
builder, loc, value);
2951 return moore::AsinhBIOp::create(
builder, loc, value);
2955 return moore::AcoshBIOp::create(
builder, loc, value);
2959 return moore::AtanhBIOp::create(
builder, loc, value);
2963 return moore::UrandomBIOp::create(
builder, loc, value);
2967 return moore::RandomBIOp::create(
builder, loc, value);
2969 .Case(
"$urandom_range",
2971 return moore::UrandomrangeBIOp::create(
builder, loc, value,
2974 .Case(
"$realtobits",
2976 return moore::RealtobitsBIOp::create(
builder, loc, value);
2978 .Case(
"$bitstoreal",
2980 return moore::BitstorealBIOp::create(
builder, loc, value);
2982 .Case(
"$shortrealtobits",
2984 return moore::ShortrealtobitsBIOp::create(
builder, loc,
2987 .Case(
"$bitstoshortreal",
2989 return moore::BitstoshortrealBIOp::create(
builder, loc,
2994 if (isa<moore::StringType>(value.getType()))
2995 return moore::StringLenOp::create(
builder, loc, value);
3000 return moore::StringToUpperOp::create(
builder, loc, value);
3004 if (isa<moore::QueueType>(value.getType())) {
3005 return moore::QueueSizeBIOp::create(
builder, loc, value);
3007 if (isa<moore::RefType>(value.getType()) &&
3008 isa<moore::AssocArrayType>(
3009 cast<moore::RefType>(value.getType())
3010 .getNestedType())) {
3011 return moore::AssocArraySizeOp::create(
builder, loc, value);
3017 if (isa<moore::RefType>(value.getType()) &&
3018 isa<moore::AssocArrayType>(
3019 cast<moore::RefType>(value.getType())
3020 .getNestedType())) {
3021 return moore::AssocArraySizeOp::create(
builder, loc, value);
3027 return moore::StringToLowerOp::create(
builder, loc, value);
3032 if (isa<moore::RefType>(value.getType()) &&
3033 isa<moore::QueueType>(
3034 cast<moore::RefType>(value.getType()).getNestedType()))
3035 return moore::QueuePopBackOp::create(
builder, loc, value);
3042 if (isa<moore::RefType>(value.getType()) &&
3043 isa<moore::QueueType>(
3044 cast<moore::RefType>(value.getType()).getNestedType()))
3045 return moore::QueuePopFrontOp::create(
builder, loc, value);
3048 .Default([&]() -> Value {
return {}; });
3049 return systemCallRes();
3054 Location loc, Value value1, Value value2) {
3055 auto systemCallRes =
3056 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
3059 return moore::StringGetOp::create(
builder, loc, value1,
3062 .Case(
"$urandom_range",
3064 return moore::UrandomrangeBIOp::create(
builder, loc, value1,
3070 if (isa<moore::RefType>(value1.getType()) &&
3071 isa<moore::AssocArrayType>(
3072 cast<moore::RefType>(value1.getType()).getNestedType()))
3073 return moore::AssocArrayExistsOp::create(
builder, loc, value1,
3077 .Default([&]() -> Value {
return {}; });
3078 return systemCallRes();
3083 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
3087 const moore::ClassHandleType &baseTy) {
3088 if (!actualTy || !baseTy)
3091 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
3092 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
3094 if (actualSym == baseSym)
3097 auto *op =
resolve(*
this, actualSym);
3098 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3101 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
3104 if (curBase == baseSym)
3106 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
3111moore::ClassHandleType
3113 llvm::StringRef fieldName, Location loc) {
3115 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
3119 auto *op =
resolve(*
this, classSym);
3120 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
3125 for (
auto &block : decl.getBody()) {
3126 for (
auto &opInBlock : block) {
3128 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
3129 if (prop.getSymName() == fieldName) {
3131 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
3138 classSym = decl.getBaseAttr();
3142 mlir::emitError(loc) <<
"unknown property `" << fieldName <<
"`";
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
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.
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.
bool isClassDerivedFrom(const moore::ClassHandleType &actualTy, const moore::ClassHandleType &baseTy)
Checks whether one class (actualTy) is derived from another class (baseTy).
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.
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={})
FailureOr< Value > convertSystemCallArity0(const slang::ast::SystemSubroutine &subroutine, Location loc)
Convert system function calls only have arity-0.
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.
FailureOr< Value > convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value)
Convert system function calls only have arity-1.
Value currentQueue
Variable that tracks the queue which we are currently converting the index expression for.
MLIRContext * getContext()
Return the MLIR context.
FailureOr< Value > convertSystemCallArity2(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value1, Value value2)
Convert system function calls with arity-2.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
llvm::SmallVector< Value, 4 > captures