10#include "slang/ast/EvalContext.h"
11#include "slang/ast/SystemSubroutine.h"
12#include "slang/syntax/AllSyntax.h"
13#include "llvm/ADT/ScopeExit.h"
16using namespace ImportVerilog;
21 if (svint.hasUnknown()) {
22 unsigned numWords = svint.getNumWords() / 2;
23 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
24 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
25 return FVInt(APInt(svint.getBitWidth(), value),
26 APInt(svint.getBitWidth(), unknown));
28 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
29 return FVInt(APInt(svint.getBitWidth(), value));
36 const slang::ConstantRange &range) {
37 auto &builder = context.
builder;
38 auto indexType = cast<moore::UnpackedType>(index.getType());
41 auto lo = range.lower();
42 auto hi = range.upper();
43 auto offset = range.isLittleEndian() ? lo : hi;
46 const bool needSigned = (lo < 0) || (hi < 0);
49 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
54 unsigned want = needSigned
55 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
56 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
59 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
62 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
66 if (range.isLittleEndian())
69 return moore::NegOp::create(builder, loc, index);
73 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
74 if (range.isLittleEndian())
75 return moore::SubOp::create(builder, loc, index, offsetConst);
77 return moore::SubOp::create(builder, loc, offsetConst, index);
82 static_assert(int(slang::TimeUnit::Seconds) == 0);
83 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
84 static_assert(int(slang::TimeUnit::Microseconds) == 2);
85 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
86 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
87 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
89 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
90 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
91 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
93 auto exp =
static_cast<unsigned>(context.
timeScale.base.unit);
96 auto scale =
static_cast<uint64_t
>(context.
timeScale.base.magnitude);
103 const slang::ast::ClassPropertySymbol &expr) {
105 auto builder = context.
builder;
111 mlir::emitError(loc) <<
"class property '" << expr.name
112 <<
"' referenced without an implicit 'this'";
116 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
117 auto fieldTy = cast<moore::UnpackedType>(type);
118 auto fieldRefTy = moore::RefType::get(fieldTy);
120 moore::ClassHandleType classTy =
121 cast<moore::ClassHandleType>(instRef.getType());
123 auto targetClassHandle =
126 false, instRef.getLoc());
128 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
129 upcastRef, fieldSym);
141 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
142 : context(context), loc(loc), builder(context.builder),
143 isLvalue(isLvalue) {}
149 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
156 Value visit(
const slang::ast::ElementSelectExpression &expr) {
158 auto value = convertLvalueOrRvalueExpression(expr.value());
163 auto derefType = value.getType();
165 derefType = cast<moore::RefType>(derefType).getNestedType();
166 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType>(
168 mlir::emitError(loc) <<
"unsupported expression: element select into "
169 << expr.value().type->toString() <<
"\n";
174 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
175 auto range = expr.value().type->getFixedRange();
176 if (
auto *constValue = expr.selector().getConstant();
177 constValue && constValue->isInteger()) {
178 assert(!constValue->hasUnknown());
179 assert(constValue->size() <= 32);
181 auto lowBit = constValue->integer().as<uint32_t>().value();
183 return moore::ExtractRefOp::create(builder, loc, resultType, value,
184 range.translateIndex(lowBit));
186 return moore::ExtractOp::create(builder, loc, resultType, value,
187 range.translateIndex(lowBit));
195 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
198 return moore::DynExtractOp::create(builder, loc, resultType, value,
203 Value visit(
const slang::ast::RangeSelectExpression &expr) {
205 auto value = convertLvalueOrRvalueExpression(expr.value());
209 std::optional<int32_t> constLeft;
210 std::optional<int32_t> constRight;
211 if (
auto *constant = expr.left().getConstant())
212 constLeft = constant->integer().as<int32_t>();
213 if (
auto *constant = expr.right().getConstant())
214 constRight = constant->integer().as<int32_t>();
220 <<
"unsupported expression: range select with non-constant bounds";
240 int32_t offsetConst = 0;
241 auto range = expr.value().type->getFixedRange();
243 using slang::ast::RangeSelectionKind;
244 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
249 assert(constRight &&
"constness checked in slang");
250 offsetConst = *constRight;
261 offsetConst = *constLeft;
272 int32_t offsetAdd = 0;
277 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
278 range.isLittleEndian()) {
279 assert(constRight &&
"constness checked in slang");
280 offsetAdd = 1 - *constRight;
286 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
287 !range.isLittleEndian()) {
288 assert(constRight &&
"constness checked in slang");
289 offsetAdd = *constRight - 1;
293 if (offsetAdd != 0) {
295 offsetDyn = moore::AddOp::create(
296 builder, loc, offsetDyn,
297 moore::ConstantOp::create(
298 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
302 offsetConst += offsetAdd;
313 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
318 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
321 return moore::DynExtractOp::create(builder, loc, resultType, value,
325 offsetConst = range.translateIndex(offsetConst);
327 return moore::ExtractRefOp::create(builder, loc, resultType, value,
330 return moore::ExtractOp::create(builder, loc, resultType, value,
337 Value visit(
const slang::ast::ConcatenationExpression &expr) {
338 SmallVector<Value> operands;
339 for (
auto *operand : expr.operands()) {
343 if (operand->type->isVoid())
345 auto value = convertLvalueOrRvalueExpression(*operand);
352 operands.push_back(value);
355 return moore::ConcatRefOp::create(builder, loc, operands);
357 return moore::ConcatOp::create(builder, loc, operands);
361 Value visit(
const slang::ast::MemberAccessExpression &expr) {
366 auto *valueType = expr.value().type.get();
367 auto memberName = builder.getStringAttr(expr.member.name);
370 if (valueType->isStruct()) {
372 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
374 auto value = convertLvalueOrRvalueExpression(expr.value());
379 return moore::StructExtractRefOp::create(builder, loc, resultType,
381 return moore::StructExtractOp::create(builder, loc, resultType,
386 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
388 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
390 auto value = convertLvalueOrRvalueExpression(expr.value());
395 return moore::UnionExtractRefOp::create(builder, loc, resultType,
397 return moore::UnionExtractOp::create(builder, loc, type, memberName,
402 if (valueType->isClass()) {
407 auto targetTy = dyn_cast<moore::ClassHandleType>(valTy);
412 auto upcastTargetTy =
424 mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.member.name);
425 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
428 Value fieldRef = moore::ClassPropertyRefOp::create(
429 builder, loc, fieldRefTy, baseVal, fieldSym);
432 return isLvalue ? fieldRef
433 : moore::ReadOp::create(builder, loc, fieldRef);
436 mlir::emitError(loc,
"expression of type ")
437 << valueType->toString() <<
" has no member fields";
449struct RvalueExprVisitor :
public ExprVisitor {
450 RvalueExprVisitor(
Context &context, Location loc)
451 : ExprVisitor(context, loc, false) {}
452 using ExprVisitor::visit;
455 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
458 return moore::ReadOp::create(builder, loc, lvalue);
462 Value visit(
const slang::ast::NamedValueExpression &expr) {
464 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
465 if (isa<moore::RefType>(value.getType())) {
466 auto readOp = moore::ReadOp::create(builder, loc, value);
469 value = readOp.getResult();
476 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
477 return moore::ReadOp::create(builder, loc, value);
481 if (
auto *
const property =
482 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
484 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
494 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
496 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
501 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
503 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
504 if (isa<moore::RefType>(value.getType())) {
505 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
508 value = readOp.getResult();
515 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
516 << expr.symbol.name <<
"`";
517 d.attachNote(hierLoc) <<
"no rvalue generated for "
518 << slang::ast::toString(expr.symbol.kind);
523 Value visit(
const slang::ast::ConversionExpression &expr) {
531 Value visit(
const slang::ast::AssignmentExpression &expr) {
539 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
547 if (!expr.isNonBlocking()) {
548 if (expr.timingControl)
551 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
558 if (expr.timingControl) {
560 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
562 ctrl->expr, moore::TimeType::get(builder.getContext()));
565 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
566 builder, loc, lhs, rhs, delay);
575 <<
"unsupported non-blocking assignment timing control: "
576 << slang::ast::toString(expr.timingControl->kind);
579 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
587 template <
class ConcreteOp>
588 Value createReduction(Value arg,
bool invert) {
592 Value result = ConcreteOp::create(builder, loc, arg);
594 result = moore::NotOp::create(builder, loc, result);
599 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
600 auto preValue = moore::ReadOp::create(builder, loc, arg);
606 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
609 auto one = moore::ConstantOp::create(
610 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
612 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
613 : moore::SubOp::create(builder, loc, preValue, one).getResult();
615 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
626 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
627 auto preValue = moore::ReadOp::create(builder, loc, arg);
630 auto ty = preValue.getType();
631 moore::RealType realTy = llvm::dyn_cast<moore::RealType>(ty);
636 if (realTy.getWidth() == moore::RealWidth::f32) {
637 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
638 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
639 oneAttr = builder.getFloatAttr(builder.getF64Type(), 1.0);
641 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
644 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
648 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
649 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
651 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
661 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
662 Type opFTy = context.
convertType(*expr.operand().type);
664 using slang::ast::UnaryOperator;
666 if (expr.op == UnaryOperator::Preincrement ||
667 expr.op == UnaryOperator::Predecrement ||
668 expr.op == UnaryOperator::Postincrement ||
669 expr.op == UnaryOperator::Postdecrement)
678 case UnaryOperator::Plus:
680 case UnaryOperator::Minus:
681 return moore::NegRealOp::create(builder, loc, arg);
683 case UnaryOperator::Preincrement:
684 return createRealIncrement(arg,
true,
false);
685 case UnaryOperator::Predecrement:
686 return createRealIncrement(arg,
false,
false);
687 case UnaryOperator::Postincrement:
688 return createRealIncrement(arg,
true,
true);
689 case UnaryOperator::Postdecrement:
690 return createRealIncrement(arg,
false,
true);
692 case UnaryOperator::LogicalNot:
696 return moore::NotOp::create(builder, loc, arg);
699 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
700 <<
" not supported with real values!\n";
706 Value visit(
const slang::ast::UnaryExpression &expr) {
708 const auto *floatType =
709 expr.operand().type->as_if<slang::ast::FloatingType>();
712 return visitRealUOp(expr);
714 using slang::ast::UnaryOperator;
716 if (expr.op == UnaryOperator::Preincrement ||
717 expr.op == UnaryOperator::Predecrement ||
718 expr.op == UnaryOperator::Postincrement ||
719 expr.op == UnaryOperator::Postdecrement)
729 case UnaryOperator::Plus:
732 case UnaryOperator::Minus:
736 return moore::NegOp::create(builder, loc, arg);
738 case UnaryOperator::BitwiseNot:
742 return moore::NotOp::create(builder, loc, arg);
744 case UnaryOperator::BitwiseAnd:
745 return createReduction<moore::ReduceAndOp>(arg,
false);
746 case UnaryOperator::BitwiseOr:
747 return createReduction<moore::ReduceOrOp>(arg,
false);
748 case UnaryOperator::BitwiseXor:
749 return createReduction<moore::ReduceXorOp>(arg,
false);
750 case UnaryOperator::BitwiseNand:
751 return createReduction<moore::ReduceAndOp>(arg,
true);
752 case UnaryOperator::BitwiseNor:
753 return createReduction<moore::ReduceOrOp>(arg,
true);
754 case UnaryOperator::BitwiseXnor:
755 return createReduction<moore::ReduceXorOp>(arg,
true);
757 case UnaryOperator::LogicalNot:
761 return moore::NotOp::create(builder, loc, arg);
763 case UnaryOperator::Preincrement:
764 return createIncrement(arg,
true,
false);
765 case UnaryOperator::Predecrement:
766 return createIncrement(arg,
false,
false);
767 case UnaryOperator::Postincrement:
768 return createIncrement(arg,
true,
true);
769 case UnaryOperator::Postdecrement:
770 return createIncrement(arg,
false,
true);
773 mlir::emitError(loc,
"unsupported unary operator");
778 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
779 std::optional<Domain> domain = std::nullopt) {
780 using slang::ast::BinaryOperator;
795 case BinaryOperator::LogicalAnd:
796 return moore::AndOp::create(builder, loc, lhs, rhs);
798 case BinaryOperator::LogicalOr:
799 return moore::OrOp::create(builder, loc, lhs, rhs);
801 case BinaryOperator::LogicalImplication: {
803 auto notLHS = moore::NotOp::create(builder, loc, lhs);
804 return moore::OrOp::create(builder, loc, notLHS, rhs);
807 case BinaryOperator::LogicalEquivalence: {
809 auto notLHS = moore::NotOp::create(builder, loc, lhs);
810 auto notRHS = moore::NotOp::create(builder, loc, rhs);
811 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
812 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
813 return moore::OrOp::create(builder, loc, both, notBoth);
817 llvm_unreachable(
"not a logical BinaryOperator");
821 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
830 using slang::ast::BinaryOperator;
832 case BinaryOperator::Add:
833 return moore::AddRealOp::create(builder, loc, lhs, rhs);
834 case BinaryOperator::Subtract:
835 return moore::SubRealOp::create(builder, loc, lhs, rhs);
836 case BinaryOperator::Multiply:
837 return moore::MulRealOp::create(builder, loc, lhs, rhs);
838 case BinaryOperator::Divide:
839 return moore::DivRealOp::create(builder, loc, lhs, rhs);
840 case BinaryOperator::Power:
841 return moore::PowRealOp::create(builder, loc, lhs, rhs);
843 case BinaryOperator::Equality:
844 return moore::EqRealOp::create(builder, loc, lhs, rhs);
845 case BinaryOperator::Inequality:
846 return moore::NeRealOp::create(builder, loc, lhs, rhs);
848 case BinaryOperator::GreaterThan:
849 return moore::FgtOp::create(builder, loc, lhs, rhs);
850 case BinaryOperator::LessThan:
851 return moore::FltOp::create(builder, loc, lhs, rhs);
852 case BinaryOperator::GreaterThanEqual:
853 return moore::FgeOp::create(builder, loc, lhs, rhs);
854 case BinaryOperator::LessThanEqual:
855 return moore::FleOp::create(builder, loc, lhs, rhs);
857 case BinaryOperator::LogicalAnd:
858 case BinaryOperator::LogicalOr:
859 case BinaryOperator::LogicalImplication:
860 case BinaryOperator::LogicalEquivalence:
861 return buildLogicalBOp(expr.op, lhs, rhs);
864 mlir::emitError(loc) <<
"Binary operator "
865 << slang::ast::toString(expr.op)
866 <<
" not supported with real valued operands!\n";
873 template <
class ConcreteOp>
874 Value createBinary(Value lhs, Value rhs) {
881 return ConcreteOp::create(builder, loc, lhs, rhs);
885 Value visit(
const slang::ast::BinaryExpression &expr) {
887 const auto *rhsFloatType =
888 expr.right().type->as_if<slang::ast::FloatingType>();
889 const auto *lhsFloatType =
890 expr.left().type->as_if<slang::ast::FloatingType>();
893 if (rhsFloatType || lhsFloatType)
894 return visitRealBOp(expr);
904 Domain domain = Domain::TwoValued;
905 if (expr.type->isFourState() || expr.left().type->isFourState() ||
906 expr.right().type->isFourState())
907 domain = Domain::FourValued;
909 using slang::ast::BinaryOperator;
911 case BinaryOperator::Add:
912 return createBinary<moore::AddOp>(lhs, rhs);
913 case BinaryOperator::Subtract:
914 return createBinary<moore::SubOp>(lhs, rhs);
915 case BinaryOperator::Multiply:
916 return createBinary<moore::MulOp>(lhs, rhs);
917 case BinaryOperator::Divide:
918 if (expr.type->isSigned())
919 return createBinary<moore::DivSOp>(lhs, rhs);
921 return createBinary<moore::DivUOp>(lhs, rhs);
922 case BinaryOperator::Mod:
923 if (expr.type->isSigned())
924 return createBinary<moore::ModSOp>(lhs, rhs);
926 return createBinary<moore::ModUOp>(lhs, rhs);
927 case BinaryOperator::Power: {
933 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
934 if (expr.type->isSigned())
935 return createBinary<moore::PowSOp>(lhs, rhsCast);
937 return createBinary<moore::PowUOp>(lhs, rhsCast);
940 case BinaryOperator::BinaryAnd:
941 return createBinary<moore::AndOp>(lhs, rhs);
942 case BinaryOperator::BinaryOr:
943 return createBinary<moore::OrOp>(lhs, rhs);
944 case BinaryOperator::BinaryXor:
945 return createBinary<moore::XorOp>(lhs, rhs);
946 case BinaryOperator::BinaryXnor: {
947 auto result = createBinary<moore::XorOp>(lhs, rhs);
950 return moore::NotOp::create(builder, loc, result);
953 case BinaryOperator::Equality:
954 if (isa<moore::UnpackedArrayType>(lhs.getType()))
955 return moore::UArrayCmpOp::create(
956 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
957 else if (isa<moore::StringType>(lhs.getType()))
958 return moore::StringCmpOp::create(
959 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
961 return createBinary<moore::EqOp>(lhs, rhs);
962 case BinaryOperator::Inequality:
963 if (isa<moore::UnpackedArrayType>(lhs.getType()))
964 return moore::UArrayCmpOp::create(
965 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
966 else if (isa<moore::StringType>(lhs.getType()))
967 return moore::StringCmpOp::create(
968 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
970 return createBinary<moore::NeOp>(lhs, rhs);
971 case BinaryOperator::CaseEquality:
972 return createBinary<moore::CaseEqOp>(lhs, rhs);
973 case BinaryOperator::CaseInequality:
974 return createBinary<moore::CaseNeOp>(lhs, rhs);
975 case BinaryOperator::WildcardEquality:
976 return createBinary<moore::WildcardEqOp>(lhs, rhs);
977 case BinaryOperator::WildcardInequality:
978 return createBinary<moore::WildcardNeOp>(lhs, rhs);
980 case BinaryOperator::GreaterThanEqual:
981 if (expr.left().type->isSigned())
982 return createBinary<moore::SgeOp>(lhs, rhs);
983 else if (isa<moore::StringType>(lhs.getType()))
984 return moore::StringCmpOp::create(
985 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
987 return createBinary<moore::UgeOp>(lhs, rhs);
988 case BinaryOperator::GreaterThan:
989 if (expr.left().type->isSigned())
990 return createBinary<moore::SgtOp>(lhs, rhs);
991 else if (isa<moore::StringType>(lhs.getType()))
992 return moore::StringCmpOp::create(
993 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
995 return createBinary<moore::UgtOp>(lhs, rhs);
996 case BinaryOperator::LessThanEqual:
997 if (expr.left().type->isSigned())
998 return createBinary<moore::SleOp>(lhs, rhs);
999 else if (isa<moore::StringType>(lhs.getType()))
1000 return moore::StringCmpOp::create(
1001 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1003 return createBinary<moore::UleOp>(lhs, rhs);
1004 case BinaryOperator::LessThan:
1005 if (expr.left().type->isSigned())
1006 return createBinary<moore::SltOp>(lhs, rhs);
1007 else if (isa<moore::StringType>(lhs.getType()))
1008 return moore::StringCmpOp::create(
1009 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1011 return createBinary<moore::UltOp>(lhs, rhs);
1013 case BinaryOperator::LogicalAnd:
1014 case BinaryOperator::LogicalOr:
1015 case BinaryOperator::LogicalImplication:
1016 case BinaryOperator::LogicalEquivalence:
1017 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1019 case BinaryOperator::LogicalShiftLeft:
1020 return createBinary<moore::ShlOp>(lhs, rhs);
1021 case BinaryOperator::LogicalShiftRight:
1022 return createBinary<moore::ShrOp>(lhs, rhs);
1023 case BinaryOperator::ArithmeticShiftLeft:
1024 return createBinary<moore::ShlOp>(lhs, rhs);
1025 case BinaryOperator::ArithmeticShiftRight: {
1032 if (expr.type->isSigned())
1033 return moore::AShrOp::create(builder, loc, lhs, rhs);
1034 return moore::ShrOp::create(builder, loc, lhs, rhs);
1038 mlir::emitError(loc,
"unsupported binary operator");
1043 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1048 Value visit(
const slang::ast::IntegerLiteral &expr) {
1053 Value visit(
const slang::ast::TimeLiteral &expr) {
1058 double value = std::round(expr.getValue() * scale);
1068 static constexpr uint64_t limit =
1069 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1070 if (value > limit) {
1071 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1075 return moore::ConstantTimeOp::create(builder, loc,
1076 static_cast<uint64_t
>(value));
1080 Value visit(
const slang::ast::ReplicationExpression &expr) {
1085 return moore::ReplicateOp::create(builder, loc, type, value);
1089 Value visit(
const slang::ast::InsideExpression &expr) {
1095 SmallVector<Value> conditions;
1098 for (
const auto *listExpr : expr.rangeList()) {
1102 if (
const auto *openRange =
1103 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
1109 if (!lowBound || !highBound)
1111 Value leftValue, rightValue;
1114 if (openRange->left().type->isSigned() ||
1115 expr.left().type->isSigned()) {
1116 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
1118 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
1120 if (openRange->right().type->isSigned() ||
1121 expr.left().type->isSigned()) {
1122 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
1124 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
1126 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
1129 if (!listExpr->type->isIntegral()) {
1130 if (listExpr->type->isUnpackedArray()) {
1132 loc,
"unpacked arrays in 'inside' expressions not supported");
1136 loc,
"only simple bit vectors supported in 'inside' expressions");
1144 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
1146 conditions.push_back(cond);
1150 auto result = conditions.back();
1151 conditions.pop_back();
1152 while (!conditions.empty()) {
1153 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1154 conditions.pop_back();
1160 Value visit(
const slang::ast::ConditionalExpression &expr) {
1164 if (expr.conditions.size() > 1) {
1165 mlir::emitError(loc)
1166 <<
"unsupported conditional expression with more than one condition";
1169 const auto &cond = expr.conditions[0];
1171 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1178 auto conditionalOp =
1179 moore::ConditionalOp::create(builder, loc, type, value);
1182 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1183 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1185 OpBuilder::InsertionGuard g(builder);
1188 builder.setInsertionPointToStart(&trueBlock);
1192 moore::YieldOp::create(builder, loc, trueValue);
1195 builder.setInsertionPointToStart(&falseBlock);
1199 moore::YieldOp::create(builder, loc, falseValue);
1201 return conditionalOp.getResult();
1205 Value visit(
const slang::ast::CallExpression &expr) {
1212 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1218 std::pair<Value, moore::ClassHandleType>
1219 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1221 moore::ClassHandleType handleTy;
1225 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1233 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1234 <<
"' called without an object";
1238 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1239 return {thisRef, handleTy};
1243 mlir::CallOpInterface
1244 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1246 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1247 SmallVector<Value> &arguments,
1248 SmallVector<Type> &resultTypes) {
1251 auto funcTy = lowering->
op.getFunctionType();
1252 auto expected0 = funcTy.getInput(0);
1253 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1257 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1260 SmallVector<Value> explicitArguments;
1261 explicitArguments.reserve(arguments.size() + 1);
1262 explicitArguments.push_back(implicitThisRef);
1263 explicitArguments.append(arguments.begin(), arguments.end());
1266 const bool isVirtual =
1267 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1270 auto calleeSym = lowering->
op.getSymName();
1272 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1276 auto funcName = subroutine->name;
1277 auto method = moore::VTableLoadMethodOp::create(
1278 builder, loc, funcTy, actualThisRef,
1279 SymbolRefAttr::get(context.
getContext(), funcName));
1280 return mlir::func::CallIndirectOp::create(builder, loc, method,
1285 Value visitCall(
const slang::ast::CallExpression &expr,
1286 const slang::ast::SubroutineSymbol *subroutine) {
1288 const bool isMethod = (subroutine->thisVar !=
nullptr);
1294 if (failed(convertedFunction))
1300 SmallVector<Value> arguments;
1301 for (
auto [callArg, declArg] :
1302 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1306 auto *expr = callArg;
1307 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1308 expr = &assign->left();
1311 if (declArg->direction == slang::ast::ArgumentDirection::In)
1317 arguments.push_back(value);
1321 auto materializeCaptureAtCall = [&](Value cap) -> Value {
1323 auto refTy = dyn_cast<moore::RefType>(cap.getType());
1325 lowering->
op.emitError(
1326 "expected captured value to be moore::RefType");
1333 Region *capRegion = [&]() -> Region * {
1334 if (
auto ba = dyn_cast<BlockArgument>(cap))
1335 return ba.getOwner()->getParent();
1336 if (
auto *def = cap.getDefiningOp())
1337 return def->getParentRegion();
1341 Region *callRegion =
1342 builder.getBlock() ? builder.getBlock()->getParent() :
nullptr;
1344 for (Region *r = callRegion; r; r = r->getParentRegion()) {
1345 if (r == capRegion) {
1352 lowering->
op.emitError()
1353 <<
"cannot materialize captured ref at call site; non-symbol "
1355 << (cap.getDefiningOp()
1356 ? cap.getDefiningOp()->getName().getStringRef()
1361 for (Value cap : lowering->captures) {
1362 Value mat = materializeCaptureAtCall(cap);
1365 arguments.push_back(mat);
1370 SmallVector<Type> resultTypes(
1371 lowering->
op.getFunctionType().getResults().begin(),
1372 lowering->
op.getFunctionType().getResults().end());
1374 mlir::CallOpInterface callOp;
1378 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1379 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1380 arguments, resultTypes);
1384 mlir::func::CallOp::create(builder, loc, lowering->
op, arguments);
1387 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1391 if (resultTypes.size() == 0)
1392 return mlir::UnrealizedConversionCastOp::create(
1393 builder, loc, moore::VoidType::get(context.
getContext()),
1401 Value visitCall(
const slang::ast::CallExpression &expr,
1402 const slang::ast::CallExpression::SystemCallInfo &info) {
1403 const auto &subroutine = *
info.subroutine;
1408 bool isAssertionCall =
1409 llvm::StringSwitch<bool>(subroutine.name)
1410 .Cases({
"$rose",
"$fell",
"$stable",
"$past"},
true)
1413 if (isAssertionCall)
1416 auto args = expr.arguments();
1418 FailureOr<Value> result;
1428 if (!subroutine.name.compare(
"$sformatf")) {
1431 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1432 if (failed(fmtValue))
1434 return fmtValue.value();
1443 switch (args.size()) {
1458 if (!value || !value2)
1479 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
1485 Value visit(
const slang::ast::StringLiteral &expr) {
1487 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1491 Value visit(
const slang::ast::RealLiteral &expr) {
1492 auto fTy = mlir::Float64Type::get(context.
getContext());
1493 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
1494 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
1499 FailureOr<SmallVector<Value>>
1500 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1501 std::variant<Type, ArrayRef<Type>> expectedTypes,
1502 unsigned replCount) {
1503 const auto &elts = expr.elements();
1504 const size_t elementCount = elts.size();
1507 const bool hasBroadcast =
1508 std::holds_alternative<Type>(expectedTypes) &&
1509 static_cast<bool>(std::get<Type>(expectedTypes));
1511 const bool hasPerElem =
1512 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1513 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1517 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1518 if (types.size() != elementCount) {
1519 mlir::emitError(loc)
1520 <<
"assignment pattern arity mismatch: expected " << types.size()
1521 <<
" elements, got " << elementCount;
1526 SmallVector<Value> converted;
1527 converted.reserve(elementCount * std::max(1u, replCount));
1530 if (!hasBroadcast && !hasPerElem) {
1532 for (
const auto *elementExpr : elts) {
1536 converted.push_back(v);
1538 }
else if (hasBroadcast) {
1540 Type want = std::get<Type>(expectedTypes);
1541 for (
const auto *elementExpr : elts) {
1546 converted.push_back(v);
1549 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1550 for (
size_t i = 0; i < elementCount; ++i) {
1551 Type want = types[i];
1552 const auto *elementExpr = elts[i];
1557 converted.push_back(v);
1561 for (
unsigned i = 1; i < replCount; ++i)
1562 converted.append(converted.begin(), converted.begin() + elementCount);
1568 Value visitAssignmentPattern(
1569 const slang::ast::AssignmentPatternExpressionBase &expr,
1570 unsigned replCount = 1) {
1572 const auto &elts = expr.elements();
1575 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1576 auto elements = convertElements(expr, {}, replCount);
1578 if (failed(elements))
1581 assert(intType.getWidth() == elements->size());
1582 std::reverse(elements->begin(), elements->end());
1583 return moore::ConcatOp::create(builder, loc, intType, *elements);
1587 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1588 SmallVector<Type> expectedTy;
1589 expectedTy.reserve(structType.getMembers().size());
1590 for (
auto member : structType.getMembers())
1591 expectedTy.push_back(member.type);
1593 FailureOr<SmallVector<Value>> elements;
1594 if (expectedTy.size() == elts.size())
1595 elements = convertElements(expr, expectedTy, replCount);
1597 elements = convertElements(expr, {}, replCount);
1599 if (failed(elements))
1602 assert(structType.getMembers().size() == elements->size());
1603 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1607 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1608 SmallVector<Type> expectedTy;
1609 expectedTy.reserve(structType.getMembers().size());
1610 for (
auto member : structType.getMembers())
1611 expectedTy.push_back(member.type);
1613 FailureOr<SmallVector<Value>> elements;
1614 if (expectedTy.size() == elts.size())
1615 elements = convertElements(expr, expectedTy, replCount);
1617 elements = convertElements(expr, {}, replCount);
1619 if (failed(elements))
1622 assert(structType.getMembers().size() == elements->size());
1624 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1628 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
1630 convertElements(expr, arrayType.getElementType(), replCount);
1632 if (failed(elements))
1635 assert(arrayType.getSize() == elements->size());
1636 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1640 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
1642 convertElements(expr, arrayType.getElementType(), replCount);
1644 if (failed(elements))
1647 assert(arrayType.getSize() == elements->size());
1648 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1651 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
1655 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
1656 return visitAssignmentPattern(expr);
1659 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
1660 return visitAssignmentPattern(expr);
1663 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
1666 assert(count &&
"Slang guarantees constant non-zero replication count");
1667 return visitAssignmentPattern(expr, *count);
1670 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1671 SmallVector<Value> operands;
1672 for (
auto stream : expr.streams()) {
1673 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1674 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1675 mlir::emitError(operandLoc)
1676 <<
"Moore only support streaming "
1677 "concatenation with fixed size 'with expression'";
1681 if (stream.constantWithWidth.has_value()) {
1683 auto type = cast<moore::UnpackedType>(value.getType());
1684 auto intType = moore::IntType::get(
1685 context.
getContext(), type.getBitSize().value(), type.getDomain());
1695 operands.push_back(value);
1699 if (operands.size() == 1) {
1702 value = operands.front();
1704 value = moore::ConcatOp::create(builder, loc, operands).getResult();
1707 if (expr.getSliceSize() == 0) {
1711 auto type = cast<moore::IntType>(value.getType());
1712 SmallVector<Value> slicedOperands;
1713 auto iterMax = type.getWidth() / expr.getSliceSize();
1714 auto remainSize = type.getWidth() % expr.getSliceSize();
1716 for (
size_t i = 0; i < iterMax; i++) {
1717 auto extractResultType = moore::IntType::get(
1718 context.
getContext(), expr.getSliceSize(), type.getDomain());
1720 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
1721 value, i * expr.getSliceSize());
1722 slicedOperands.push_back(extracted);
1726 auto extractResultType = moore::IntType::get(
1727 context.
getContext(), remainSize, type.getDomain());
1730 moore::ExtractOp::create(builder, loc, extractResultType, value,
1731 iterMax * expr.getSliceSize());
1732 slicedOperands.push_back(extracted);
1735 return moore::ConcatOp::create(builder, loc, slicedOperands);
1738 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1754 Value visit(
const slang::ast::NewClassExpression &expr) {
1756 auto classTy = dyn_cast<moore::ClassHandleType>(type);
1762 if (!classTy && expr.isSuperClass) {
1764 if (!newObj || !newObj.getType() ||
1765 !isa<moore::ClassHandleType>(newObj.getType())) {
1766 mlir::emitError(loc) <<
"implicit this ref was not set while "
1767 "converting new class function";
1770 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
1772 cast<moore::ClassDeclOp>(*context.
symbolTable.lookupNearestSymbolFrom(
1774 auto baseClassSym = classDecl.getBase();
1775 classTy = circt::moore::ClassHandleType::get(context.
getContext(),
1776 baseClassSym.value());
1779 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
1782 const auto *constructor = expr.constructorCall();
1787 if (
const auto *callConstructor =
1788 constructor->as_if<slang::ast::CallExpression>())
1789 if (
const auto *subroutine =
1790 std::get_if<const slang::ast::SubroutineSymbol *>(
1791 &callConstructor->subroutine)) {
1794 if (!(*subroutine)->thisVar) {
1795 mlir::emitError(loc) <<
"Expected subroutine called by new to use an "
1796 "implicit this reference";
1805 llvm::make_scope_exit([&] { context.
currentThisRef = savedThis; });
1807 if (!visitCall(*callConstructor, *subroutine))
1816 template <
typename T>
1817 Value visit(T &&node) {
1818 mlir::emitError(loc,
"unsupported expression: ")
1819 << slang::ast::toString(node.kind);
1823 Value visitInvalid(
const slang::ast::Expression &expr) {
1824 mlir::emitError(loc,
"invalid expression");
1835struct LvalueExprVisitor :
public ExprVisitor {
1836 LvalueExprVisitor(
Context &context, Location loc)
1837 : ExprVisitor(context, loc, true) {}
1838 using ExprVisitor::visit;
1841 Value visit(
const slang::ast::NamedValueExpression &expr) {
1843 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1848 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
1850 if (
auto *
const property =
1851 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
1855 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
1857 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1862 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1864 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1869 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
1873 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1874 << expr.symbol.name <<
"`";
1876 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1880 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1881 SmallVector<Value> operands;
1882 for (
auto stream : expr.streams()) {
1883 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1884 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1885 mlir::emitError(operandLoc)
1886 <<
"Moore only support streaming "
1887 "concatenation with fixed size 'with expression'";
1891 if (stream.constantWithWidth.has_value()) {
1893 auto type = cast<moore::UnpackedType>(
1894 cast<moore::RefType>(value.getType()).getNestedType());
1895 auto intType = moore::RefType::get(moore::IntType::get(
1896 context.
getContext(), type.getBitSize().value(), type.getDomain()));
1905 operands.push_back(value);
1908 if (operands.size() == 1) {
1911 value = operands.front();
1913 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
1916 if (expr.getSliceSize() == 0) {
1920 auto type = cast<moore::IntType>(
1921 cast<moore::RefType>(value.getType()).getNestedType());
1922 SmallVector<Value> slicedOperands;
1923 auto widthSum = type.getWidth();
1924 auto domain = type.getDomain();
1925 auto iterMax = widthSum / expr.getSliceSize();
1926 auto remainSize = widthSum % expr.getSliceSize();
1928 for (
size_t i = 0; i < iterMax; i++) {
1929 auto extractResultType = moore::RefType::get(moore::IntType::get(
1930 context.
getContext(), expr.getSliceSize(), domain));
1932 auto extracted = moore::ExtractRefOp::create(
1933 builder, loc, extractResultType, value, i * expr.getSliceSize());
1934 slicedOperands.push_back(extracted);
1938 auto extractResultType = moore::RefType::get(
1939 moore::IntType::get(context.
getContext(), remainSize, domain));
1942 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
1943 iterMax * expr.getSliceSize());
1944 slicedOperands.push_back(extracted);
1947 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
1951 template <
typename T>
1952 Value visit(T &&node) {
1956 Value visitInvalid(
const slang::ast::Expression &expr) {
1957 mlir::emitError(loc,
"invalid expression");
1967Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
1968 Type requiredType) {
1970 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
1971 if (value && requiredType)
1979 return expr.visit(LvalueExprVisitor(*
this, loc));
1987 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
1988 if (type.getBitSize() == 1)
1990 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
1991 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
1992 mlir::emitError(value.getLoc(),
"expression of type ")
1993 << value.getType() <<
" cannot be cast to a boolean";
1999 const slang::ast::Type &astType,
2001 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2005 if (svreal.isShortReal() &&
2006 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2007 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2008 }
else if (svreal.isReal() &&
2009 floatType->floatKind == slang::ast::FloatingType::Real) {
2010 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2012 mlir::emitError(loc) <<
"invalid real constant";
2016 return moore::ConstantRealOp::create(
builder, loc, attr);
2021 const slang::ast::Type &astType,
2023 slang::ConstantValue intVal = stringLiteral.convertToInt();
2024 auto effectiveWidth = intVal.getEffectiveWidth();
2025 if (!effectiveWidth)
2028 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2030 if (astType.isString()) {
2031 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2032 stringLiteral.toString())
2034 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2041 const slang::ast::Type &astType, Location loc) {
2046 bool typeIsFourValued =
false;
2047 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2051 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2052 fvint.hasUnknown() || typeIsFourValued
2055 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2060 const slang::ConstantValue &constant,
2061 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2069 if (astType.elementType.isIntegral())
2070 bitWidth = astType.elementType.getBitWidth();
2074 bool typeIsFourValued =
false;
2077 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2088 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2090 auto arrType = moore::UnpackedArrayType::get(
2091 getContext(), constant.elements().size(), intType);
2093 llvm::SmallVector<mlir::Value> elemVals;
2094 moore::ConstantOp constOp;
2096 mlir::OpBuilder::InsertionGuard guard(
builder);
2099 for (
auto elem : constant.elements()) {
2101 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2102 elemVals.push_back(constOp.getResult());
2107 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2109 return arrayOp.getResult();
2113 const slang::ast::Type &type, Location loc) {
2115 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2117 if (constant.isInteger())
2119 if (constant.isReal() || constant.isShortReal())
2121 if (constant.isString())
2129 using slang::ast::EvalFlags;
2130 slang::ast::EvalContext evalContext(
2132 slang::ast::LookupLocation::max),
2133 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2134 return expr.eval(evalContext);
2143 auto type = moore::IntType::get(
getContext(), 1, domain);
2150 if (isa<moore::IntType>(value.getType()))
2157 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2158 if (
auto sbvType = packed.getSimpleBitVector())
2161 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2162 <<
" cannot be cast to a simple bit vector";
2171 if (isa<moore::IntType>(value.getType()))
2174 auto &builder = context.
builder;
2175 auto packedType = cast<moore::PackedType>(value.getType());
2176 auto intType = packedType.getSimpleBitVector();
2181 if (isa<moore::TimeType>(packedType) &&
2183 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2184 auto scale = moore::ConstantOp::create(builder, loc, intType,
2186 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2192 if (packedType.containsTimeType()) {
2193 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2194 <<
" cannot be converted to " << intType
2195 <<
"; contains a time type";
2200 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2208 Value value, Location loc) {
2209 if (value.getType() == packedType)
2212 auto &builder = context.
builder;
2213 auto intType = cast<moore::IntType>(value.getType());
2218 if (isa<moore::TimeType>(packedType) &&
2220 auto scale = moore::ConstantOp::create(builder, loc, intType,
2222 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2223 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2230 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2231 <<
" cannot be converted to " << packedType
2232 <<
"; contains a time type";
2237 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2243 moore::ClassHandleType expectedHandleTy) {
2244 auto loc = actualHandle.getLoc();
2246 auto actualTy = actualHandle.getType();
2247 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2248 if (!actualHandleTy) {
2249 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2255 if (actualHandleTy == expectedHandleTy)
2256 return actualHandle;
2259 mlir::emitError(loc)
2260 <<
"receiver class " << actualHandleTy.getClassSym()
2261 <<
" is not the same as, or derived from, expected base class "
2262 << expectedHandleTy.getClassSym().getRootReference();
2267 auto casted = moore::ClassUpcastOp::create(context.
builder, loc,
2268 expectedHandleTy, actualHandle)
2276 if (type == value.getType())
2281 auto dstPacked = dyn_cast<moore::PackedType>(type);
2282 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2283 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2284 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2286 if (dstInt && srcInt) {
2294 auto resizedType = moore::IntType::get(
2295 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2296 if (dstInt.getWidth() < srcInt.getWidth()) {
2297 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2298 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2300 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2302 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2306 if (dstInt.getDomain() != srcInt.getDomain()) {
2308 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2310 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2318 assert(value.getType() == type);
2323 if (isa<moore::StringType>(type) &&
2324 isa<moore::FormatStringType>(value.getType())) {
2325 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2329 if (isa<moore::FormatStringType>(type) &&
2330 isa<moore::StringType>(value.getType())) {
2331 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2335 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2336 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2337 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2345 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2348 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2353 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2356 return builder.createOrFold<moore::IntToRealOp>(loc, type, twoValInt);
2359 if (isa<moore::ClassHandleType>(type) &&
2360 isa<moore::ClassHandleType>(value.getType()))
2364 if (value.getType() != type)
2365 value = moore::ConversionOp::create(
builder, loc, type, value);
2373 auto systemCallRes =
2374 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2377 return moore::UrandomBIOp::create(
builder, loc,
nullptr);
2381 return moore::RandomBIOp::create(
builder, loc,
nullptr);
2385 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2388 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2391 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2392 .Default([&]() -> Value {
return {}; });
2393 return systemCallRes();
2398 Location loc, Value value) {
2399 auto systemCallRes =
2400 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2402 .Case(
"$signed", [&]() {
return value; })
2403 .Case(
"$unsigned", [&]() {
return value; })
2407 [&]() -> FailureOr<Value> {
2411 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
2415 return moore::LnBIOp::create(
builder, loc, value);
2419 return moore::Log10BIOp::create(
builder, loc, value);
2423 return moore::SinBIOp::create(
builder, loc, value);
2427 return moore::CosBIOp::create(
builder, loc, value);
2431 return moore::TanBIOp::create(
builder, loc, value);
2435 return moore::ExpBIOp::create(
builder, loc, value);
2439 return moore::SqrtBIOp::create(
builder, loc, value);
2443 return moore::FloorBIOp::create(
builder, loc, value);
2447 return moore::CeilBIOp::create(
builder, loc, value);
2451 return moore::AsinBIOp::create(
builder, loc, value);
2455 return moore::AcosBIOp::create(
builder, loc, value);
2459 return moore::AtanBIOp::create(
builder, loc, value);
2463 return moore::SinhBIOp::create(
builder, loc, value);
2467 return moore::CoshBIOp::create(
builder, loc, value);
2471 return moore::TanhBIOp::create(
builder, loc, value);
2475 return moore::AsinhBIOp::create(
builder, loc, value);
2479 return moore::AcoshBIOp::create(
builder, loc, value);
2483 return moore::AtanhBIOp::create(
builder, loc, value);
2487 return moore::UrandomBIOp::create(
builder, loc, value);
2491 return moore::RandomBIOp::create(
builder, loc, value);
2493 .Case(
"$realtobits",
2495 return moore::RealtobitsBIOp::create(
builder, loc, value);
2497 .Case(
"$bitstoreal",
2499 return moore::BitstorealBIOp::create(
builder, loc, value);
2501 .Case(
"$shortrealtobits",
2503 return moore::ShortrealtobitsBIOp::create(
builder, loc,
2506 .Case(
"$bitstoshortreal",
2508 return moore::BitstoshortrealBIOp::create(
builder, loc,
2513 if (isa<moore::StringType>(value.getType()))
2514 return moore::StringLenOp::create(
builder, loc, value);
2519 return moore::StringToUpperOp::create(
builder, loc, value);
2523 return moore::StringToLowerOp::create(
builder, loc, value);
2525 .Default([&]() -> Value {
return {}; });
2526 return systemCallRes();
2531 Location loc, Value value1, Value value2) {
2532 auto systemCallRes =
2533 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2536 return moore::StringGetCOp::create(
builder, loc, value1,
2539 .Default([&]() -> Value {
return {}; });
2540 return systemCallRes();
2549 const moore::ClassHandleType &baseTy) {
2550 if (!actualTy || !baseTy)
2553 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
2554 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
2556 if (actualSym == baseSym)
2559 auto *op =
resolve(*
this, actualSym);
2560 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2563 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
2566 if (curBase == baseSym)
2568 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
2573moore::ClassHandleType
2575 llvm::StringRef fieldName) {
2576 if (!actualTy || fieldName.empty())
2580 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
2584 auto *op =
resolve(*
this, classSym);
2585 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2590 for (
auto &block : decl.getBody()) {
2591 for (
auto &opInBlock : block) {
2593 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
2594 if (prop.getSymName() == fieldName) {
2596 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
2603 classSym = decl.getBaseAttr();
assert(baseType &&"element must be base type")
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
LogicalResult convertFunction(const slang::ast::SubroutineSymbol &subroutine)
Convert a function.
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
LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl)
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.
Value convertAssertionCallExpression(const slang::ast::CallExpression &expr, const slang::ast::CallExpression::SystemCallInfo &info, Location loc)
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).
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.
slang::TimeScale timeScale
The time scale currently in effect.
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
std::function< void(mlir::Operation *)> variableAssignCallback
A listener called for every variable or net being assigned.
FailureOr< Value > convertFormatString(std::span< const slang::ast::Expression *const > arguments, Location loc, moore::IntFormat defaultFormat=moore::IntFormat::Decimal, bool appendNewline=false)
Convert a list of string literal arguments with formatting specifiers and arguments to be interpolate...
Value getImplicitThisRef() const
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.
moore::ClassHandleType getAncestorClassWithProperty(const moore::ClassHandleType &actualTy, StringRef fieldName)
Tries to find the closest base class of actualTy that carries a property with name fieldName.
Value materializeString(const slang::ConstantValue &string, const slang::ast::Type &astType, Location loc)
Helper function to materialize a string as an SSA value.
Value currentThisRef
Variable to track the value of the current function's implicit this reference.
FailureOr< Value > convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value)
Convert system function calls only have arity-1.
mlir::ModuleOp intoModuleOp
SymbolTable symbolTable
A symbol table of the MLIR module we are emitting into.
FunctionLowering * declareFunction(const slang::ast::SubroutineSymbol &subroutine)
Convert a function and its arguments to a function declaration in the IR.
Value convertAssertionExpression(const slang::ast::AssertionExpr &expr, Location loc)
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.
SmallVector< Value > lvalueStack
A stack of assignment left-hand side values.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
llvm::SmallVector< Value, 4 > captures