10#include "slang/ast/EvalContext.h"
11#include "slang/ast/SystemSubroutine.h"
12#include "slang/syntax/AllSyntax.h"
15using namespace ImportVerilog;
20 if (svint.hasUnknown()) {
21 unsigned numWords = svint.getNumWords() / 2;
22 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
23 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
24 return FVInt(APInt(svint.getBitWidth(), value),
25 APInt(svint.getBitWidth(), unknown));
27 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
28 return FVInt(APInt(svint.getBitWidth(), value));
35 const slang::ConstantRange &range) {
36 auto &builder = context.
builder;
37 auto indexType = cast<moore::UnpackedType>(index.getType());
38 auto bw = std::max(llvm::Log2_32_Ceil(std::max(std::abs(range.lower()),
39 std::abs(range.upper()))),
40 indexType.getBitSize().value());
42 auto offset = range.isLittleEndian() ? range.lower() : range.upper();
43 bool isSigned = (offset < 0);
45 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
49 if (range.isLittleEndian())
52 return moore::NegOp::create(builder, loc, index);
56 moore::ConstantOp::create(builder, loc, intType, offset, isSigned);
57 if (range.isLittleEndian())
58 return moore::SubOp::create(builder, loc, index, offsetConst);
60 return moore::SubOp::create(builder, loc, offsetConst, index);
65 static_assert(int(slang::TimeUnit::Seconds) == 0);
66 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
67 static_assert(int(slang::TimeUnit::Microseconds) == 2);
68 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
69 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
70 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
72 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
73 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
74 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
76 auto exp =
static_cast<unsigned>(context.
timeScale.base.unit);
79 auto scale =
static_cast<uint64_t
>(context.
timeScale.base.magnitude);
93 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
94 : context(context), loc(loc), builder(context.builder),
101 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
108 Value visit(
const slang::ast::ElementSelectExpression &expr) {
110 auto value = convertLvalueOrRvalueExpression(expr.value());
115 auto derefType = value.getType();
117 derefType = cast<moore::RefType>(derefType).getNestedType();
118 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType>(
120 mlir::emitError(loc) <<
"unsupported expression: element select into "
121 << expr.value().type->toString() <<
"\n";
126 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
127 auto range = expr.value().type->getFixedRange();
128 if (
auto *constValue = expr.selector().getConstant();
129 constValue && constValue->isInteger()) {
130 assert(!constValue->hasUnknown());
131 assert(constValue->size() <= 32);
133 auto lowBit = constValue->integer().as<uint32_t>().value();
135 return moore::ExtractRefOp::create(builder, loc, resultType, value,
136 range.translateIndex(lowBit));
138 return moore::ExtractOp::create(builder, loc, resultType, value,
139 range.translateIndex(lowBit));
147 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
150 return moore::DynExtractOp::create(builder, loc, resultType, value,
155 Value visit(
const slang::ast::RangeSelectExpression &expr) {
157 auto value = convertLvalueOrRvalueExpression(expr.value());
161 std::optional<int32_t> constLeft;
162 std::optional<int32_t> constRight;
163 if (
auto *constant = expr.left().getConstant())
164 constLeft = constant->integer().as<int32_t>();
165 if (
auto *constant = expr.right().getConstant())
166 constRight = constant->integer().as<int32_t>();
172 <<
"unsupported expression: range select with non-constant bounds";
192 int32_t offsetConst = 0;
193 auto range = expr.value().type->getFixedRange();
195 using slang::ast::RangeSelectionKind;
196 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
201 assert(constRight &&
"constness checked in slang");
202 offsetConst = *constRight;
213 offsetConst = *constLeft;
224 int32_t offsetAdd = 0;
229 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
230 range.isLittleEndian()) {
231 assert(constRight &&
"constness checked in slang");
232 offsetAdd = 1 - *constRight;
238 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
239 !range.isLittleEndian()) {
240 assert(constRight &&
"constness checked in slang");
241 offsetAdd = *constRight - 1;
245 if (offsetAdd != 0) {
247 offsetDyn = moore::AddOp::create(
248 builder, loc, offsetDyn,
249 moore::ConstantOp::create(
250 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
254 offsetConst += offsetAdd;
265 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
270 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
273 return moore::DynExtractOp::create(builder, loc, resultType, value,
277 offsetConst = range.translateIndex(offsetConst);
279 return moore::ExtractRefOp::create(builder, loc, resultType, value,
282 return moore::ExtractOp::create(builder, loc, resultType, value,
289 Value visit(
const slang::ast::ConcatenationExpression &expr) {
290 SmallVector<Value> operands;
291 for (
auto *operand : expr.operands()) {
295 if (operand->type->isVoid())
297 auto value = convertLvalueOrRvalueExpression(*operand);
304 operands.push_back(value);
307 return moore::ConcatRefOp::create(builder, loc, operands);
309 return moore::ConcatOp::create(builder, loc, operands);
313 Value visit(
const slang::ast::MemberAccessExpression &expr) {
315 auto valueType = expr.value().type;
316 auto value = convertLvalueOrRvalueExpression(expr.value());
321 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
322 auto memberName = builder.getStringAttr(expr.member.name);
325 if (valueType->isStruct()) {
327 return moore::StructExtractRefOp::create(builder, loc, resultType,
330 return moore::StructExtractOp::create(builder, loc, resultType,
335 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
337 return moore::UnionExtractRefOp::create(builder, loc, resultType,
340 return moore::UnionExtractOp::create(builder, loc, type, memberName,
344 mlir::emitError(loc,
"expression of type ")
345 << value.getType() <<
" has no member fields";
357struct RvalueExprVisitor :
public ExprVisitor {
358 RvalueExprVisitor(
Context &context, Location loc)
359 : ExprVisitor(context, loc, false) {}
360 using ExprVisitor::visit;
363 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
366 return moore::ReadOp::create(builder, loc, lvalue);
370 Value visit(
const slang::ast::NamedValueExpression &expr) {
371 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
372 if (isa<moore::RefType>(value.getType())) {
373 auto readOp = moore::ReadOp::create(builder, loc, value);
376 value = readOp.getResult();
388 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
390 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
395 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
397 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
398 if (isa<moore::RefType>(value.getType())) {
399 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
402 value = readOp.getResult();
409 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
410 << expr.symbol.name <<
"`";
411 d.attachNote(hierLoc) <<
"no rvalue generated for "
412 << slang::ast::toString(expr.symbol.kind);
417 Value visit(
const slang::ast::ConversionExpression &expr) {
425 Value visit(
const slang::ast::AssignmentExpression &expr) {
432 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
437 if (expr.timingControl) {
439 mlir::emitError(loc,
"delayed assignments not supported");
443 if (expr.isNonBlocking())
444 moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
446 moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
452 template <
class ConcreteOp>
453 Value createReduction(Value arg,
bool invert) {
457 Value result = ConcreteOp::create(builder, loc, arg);
459 result = moore::NotOp::create(builder, loc, result);
464 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
465 auto preValue = moore::ReadOp::create(builder, loc, arg);
471 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
474 auto one = moore::ConstantOp::create(
475 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
477 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
478 : moore::SubOp::create(builder, loc, preValue, one).getResult();
479 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
487 Value visit(
const slang::ast::UnaryExpression &expr) {
488 using slang::ast::UnaryOperator;
490 if (expr.op == UnaryOperator::Preincrement ||
491 expr.op == UnaryOperator::Predecrement ||
492 expr.op == UnaryOperator::Postincrement ||
493 expr.op == UnaryOperator::Postdecrement)
503 case UnaryOperator::Plus:
506 case UnaryOperator::Minus:
510 return moore::NegOp::create(builder, loc, arg);
512 case UnaryOperator::BitwiseNot:
516 return moore::NotOp::create(builder, loc, arg);
518 case UnaryOperator::BitwiseAnd:
519 return createReduction<moore::ReduceAndOp>(arg,
false);
520 case UnaryOperator::BitwiseOr:
521 return createReduction<moore::ReduceOrOp>(arg,
false);
522 case UnaryOperator::BitwiseXor:
523 return createReduction<moore::ReduceXorOp>(arg,
false);
524 case UnaryOperator::BitwiseNand:
525 return createReduction<moore::ReduceAndOp>(arg,
true);
526 case UnaryOperator::BitwiseNor:
527 return createReduction<moore::ReduceOrOp>(arg,
true);
528 case UnaryOperator::BitwiseXnor:
529 return createReduction<moore::ReduceXorOp>(arg,
true);
531 case UnaryOperator::LogicalNot:
535 return moore::NotOp::create(builder, loc, arg);
537 case UnaryOperator::Preincrement:
538 return createIncrement(arg,
true,
false);
539 case UnaryOperator::Predecrement:
540 return createIncrement(arg,
false,
false);
541 case UnaryOperator::Postincrement:
542 return createIncrement(arg,
true,
true);
543 case UnaryOperator::Postdecrement:
544 return createIncrement(arg,
false,
true);
547 mlir::emitError(loc,
"unsupported unary operator");
553 template <
class ConcreteOp>
554 Value createBinary(Value lhs, Value rhs) {
561 return ConcreteOp::create(builder, loc, lhs, rhs);
565 Value visit(
const slang::ast::BinaryExpression &expr) {
574 Domain domain = Domain::TwoValued;
575 if (expr.type->isFourState() || expr.left().type->isFourState() ||
576 expr.right().type->isFourState())
577 domain = Domain::FourValued;
579 using slang::ast::BinaryOperator;
581 case BinaryOperator::Add:
582 return createBinary<moore::AddOp>(lhs, rhs);
583 case BinaryOperator::Subtract:
584 return createBinary<moore::SubOp>(lhs, rhs);
585 case BinaryOperator::Multiply:
586 return createBinary<moore::MulOp>(lhs, rhs);
587 case BinaryOperator::Divide:
588 if (expr.type->isSigned())
589 return createBinary<moore::DivSOp>(lhs, rhs);
591 return createBinary<moore::DivUOp>(lhs, rhs);
592 case BinaryOperator::Mod:
593 if (expr.type->isSigned())
594 return createBinary<moore::ModSOp>(lhs, rhs);
596 return createBinary<moore::ModUOp>(lhs, rhs);
597 case BinaryOperator::Power: {
603 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
604 if (expr.type->isSigned())
605 return createBinary<moore::PowSOp>(lhs, rhsCast);
607 return createBinary<moore::PowUOp>(lhs, rhsCast);
610 case BinaryOperator::BinaryAnd:
611 return createBinary<moore::AndOp>(lhs, rhs);
612 case BinaryOperator::BinaryOr:
613 return createBinary<moore::OrOp>(lhs, rhs);
614 case BinaryOperator::BinaryXor:
615 return createBinary<moore::XorOp>(lhs, rhs);
616 case BinaryOperator::BinaryXnor: {
617 auto result = createBinary<moore::XorOp>(lhs, rhs);
620 return moore::NotOp::create(builder, loc, result);
623 case BinaryOperator::Equality:
624 if (isa<moore::UnpackedArrayType>(lhs.getType()))
625 return moore::UArrayCmpOp::create(
626 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
627 else if (isa<moore::StringType>(lhs.getType()))
628 return moore::StringCmpOp::create(
629 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
631 return createBinary<moore::EqOp>(lhs, rhs);
632 case BinaryOperator::Inequality:
633 if (isa<moore::UnpackedArrayType>(lhs.getType()))
634 return moore::UArrayCmpOp::create(
635 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
636 else if (isa<moore::StringType>(lhs.getType()))
637 return moore::StringCmpOp::create(
638 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
640 return createBinary<moore::NeOp>(lhs, rhs);
641 case BinaryOperator::CaseEquality:
642 return createBinary<moore::CaseEqOp>(lhs, rhs);
643 case BinaryOperator::CaseInequality:
644 return createBinary<moore::CaseNeOp>(lhs, rhs);
645 case BinaryOperator::WildcardEquality:
646 return createBinary<moore::WildcardEqOp>(lhs, rhs);
647 case BinaryOperator::WildcardInequality:
648 return createBinary<moore::WildcardNeOp>(lhs, rhs);
650 case BinaryOperator::GreaterThanEqual:
651 if (expr.left().type->isSigned())
652 return createBinary<moore::SgeOp>(lhs, rhs);
653 else if (isa<moore::StringType>(lhs.getType()))
654 return moore::StringCmpOp::create(
655 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
657 return createBinary<moore::UgeOp>(lhs, rhs);
658 case BinaryOperator::GreaterThan:
659 if (expr.left().type->isSigned())
660 return createBinary<moore::SgtOp>(lhs, rhs);
661 else if (isa<moore::StringType>(lhs.getType()))
662 return moore::StringCmpOp::create(
663 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
665 return createBinary<moore::UgtOp>(lhs, rhs);
666 case BinaryOperator::LessThanEqual:
667 if (expr.left().type->isSigned())
668 return createBinary<moore::SleOp>(lhs, rhs);
669 else if (isa<moore::StringType>(lhs.getType()))
670 return moore::StringCmpOp::create(
671 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
673 return createBinary<moore::UleOp>(lhs, rhs);
674 case BinaryOperator::LessThan:
675 if (expr.left().type->isSigned())
676 return createBinary<moore::SltOp>(lhs, rhs);
677 else if (isa<moore::StringType>(lhs.getType()))
678 return moore::StringCmpOp::create(
679 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
681 return createBinary<moore::UltOp>(lhs, rhs);
684 case BinaryOperator::LogicalAnd: {
693 return moore::AndOp::create(builder, loc, lhs, rhs);
695 case BinaryOperator::LogicalOr: {
704 return moore::OrOp::create(builder, loc, lhs, rhs);
706 case BinaryOperator::LogicalImplication: {
714 auto notLHS = moore::NotOp::create(builder, loc, lhs);
715 return moore::OrOp::create(builder, loc, notLHS, rhs);
717 case BinaryOperator::LogicalEquivalence: {
725 auto notLHS = moore::NotOp::create(builder, loc, lhs);
726 auto notRHS = moore::NotOp::create(builder, loc, rhs);
727 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
728 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
729 return moore::OrOp::create(builder, loc, both, notBoth);
732 case BinaryOperator::LogicalShiftLeft:
733 return createBinary<moore::ShlOp>(lhs, rhs);
734 case BinaryOperator::LogicalShiftRight:
735 return createBinary<moore::ShrOp>(lhs, rhs);
736 case BinaryOperator::ArithmeticShiftLeft:
737 return createBinary<moore::ShlOp>(lhs, rhs);
738 case BinaryOperator::ArithmeticShiftRight: {
745 if (expr.type->isSigned())
746 return moore::AShrOp::create(builder, loc, lhs, rhs);
747 return moore::ShrOp::create(builder, loc, lhs, rhs);
751 mlir::emitError(loc,
"unsupported binary operator");
756 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
761 Value visit(
const slang::ast::IntegerLiteral &expr) {
766 Value visit(
const slang::ast::TimeLiteral &expr) {
771 double value = std::round(expr.getValue() * scale);
781 static constexpr uint64_t limit =
782 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
784 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
788 return moore::ConstantTimeOp::create(builder, loc,
789 static_cast<uint64_t
>(value));
793 Value visit(
const slang::ast::ReplicationExpression &expr) {
798 return moore::ReplicateOp::create(builder, loc, type, value);
802 Value visit(
const slang::ast::InsideExpression &expr) {
808 SmallVector<Value> conditions;
811 for (
const auto *listExpr : expr.rangeList()) {
815 if (
const auto *openRange =
816 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
822 if (!lowBound || !highBound)
824 Value leftValue, rightValue;
827 if (openRange->left().type->isSigned() ||
828 expr.left().type->isSigned()) {
829 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
831 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
833 if (openRange->right().type->isSigned() ||
834 expr.left().type->isSigned()) {
835 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
837 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
839 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
842 if (!listExpr->type->isIntegral()) {
843 if (listExpr->type->isUnpackedArray()) {
845 loc,
"unpacked arrays in 'inside' expressions not supported");
849 loc,
"only simple bit vectors supported in 'inside' expressions");
857 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
859 conditions.push_back(cond);
863 auto result = conditions.back();
864 conditions.pop_back();
865 while (!conditions.empty()) {
866 result = moore::OrOp::create(builder, loc, conditions.back(), result);
867 conditions.pop_back();
873 Value visit(
const slang::ast::ConditionalExpression &expr) {
877 if (expr.conditions.size() > 1) {
879 <<
"unsupported conditional expression with more than one condition";
882 const auto &cond = expr.conditions[0];
884 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
892 moore::ConditionalOp::create(builder, loc, type, value);
895 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
896 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
898 OpBuilder::InsertionGuard g(builder);
901 builder.setInsertionPointToStart(&trueBlock);
905 moore::YieldOp::create(builder, loc, trueValue);
908 builder.setInsertionPointToStart(&falseBlock);
912 moore::YieldOp::create(builder, loc, falseValue);
914 return conditionalOp.getResult();
918 Value visit(
const slang::ast::CallExpression &expr) {
920 if (expr.thisClass()) {
921 mlir::emitError(loc,
"unsupported class method call");
931 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
936 Value visitCall(
const slang::ast::CallExpression &expr,
937 const slang::ast::SubroutineSymbol *subroutine) {
945 SmallVector<Value> arguments;
946 for (
auto [callArg, declArg] :
947 llvm::zip(expr.arguments(), subroutine->getArguments())) {
951 auto *expr = callArg;
952 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
953 expr = &assign->left();
956 if (declArg->direction == slang::ast::ArgumentDirection::In)
962 arguments.push_back(value);
967 mlir::func::CallOp::create(builder, loc, lowering->op, arguments);
972 if (callOp.getNumResults() == 0)
973 return mlir::UnrealizedConversionCastOp::create(
974 builder, loc, moore::VoidType::get(context.
getContext()),
978 return callOp.getResult(0);
982 Value visitCall(
const slang::ast::CallExpression &expr,
983 const slang::ast::CallExpression::SystemCallInfo &info) {
984 const auto &subroutine = *
info.subroutine;
989 bool isAssertionCall =
990 llvm::StringSwitch<bool>(subroutine.name)
991 .Cases(
"$rose",
"$fell",
"$stable",
"$past",
true)
997 auto args = expr.arguments();
999 FailureOr<Value> result;
1008 if (!subroutine.name.compare(
"$sformatf")) {
1011 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1012 if (failed(fmtValue))
1014 return fmtValue.value();
1017 switch (args.size()) {
1030 mlir::emitError(loc)
1031 <<
"system call with more than 1 argument is not supported";
1039 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
1045 Value visit(
const slang::ast::StringLiteral &expr) {
1047 return moore::StringConstantOp::create(builder, loc, type, expr.getValue());
1051 Value visit(
const slang::ast::RealLiteral &expr) {
1052 return moore::RealLiteralOp::create(
1053 builder, loc, builder.getF64FloatAttr(expr.getValue()));
1058 FailureOr<SmallVector<Value>>
1059 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1060 std::variant<Type, ArrayRef<Type>> expectedTypes,
1061 unsigned replCount) {
1062 const auto &elts = expr.elements();
1063 const size_t elementCount = elts.size();
1066 const bool hasBroadcast =
1067 std::holds_alternative<Type>(expectedTypes) &&
1068 static_cast<bool>(std::get<Type>(expectedTypes));
1070 const bool hasPerElem =
1071 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1072 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1076 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1077 if (types.size() != elementCount) {
1078 mlir::emitError(loc)
1079 <<
"assignment pattern arity mismatch: expected " << types.size()
1080 <<
" elements, got " << elementCount;
1085 SmallVector<Value> converted;
1086 converted.reserve(elementCount * std::max(1u, replCount));
1089 if (!hasBroadcast && !hasPerElem) {
1091 for (
const auto *elementExpr : elts) {
1095 converted.push_back(v);
1097 }
else if (hasBroadcast) {
1099 Type want = std::get<Type>(expectedTypes);
1100 for (
const auto *elementExpr : elts) {
1105 converted.push_back(v);
1108 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1109 for (
size_t i = 0; i < elementCount; ++i) {
1110 Type want = types[i];
1111 const auto *elementExpr = elts[i];
1116 converted.push_back(v);
1120 for (
unsigned i = 1; i < replCount; ++i)
1121 converted.append(converted.begin(), converted.begin() + elementCount);
1127 Value visitAssignmentPattern(
1128 const slang::ast::AssignmentPatternExpressionBase &expr,
1129 unsigned replCount = 1) {
1131 const auto &elts = expr.elements();
1134 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1135 auto elements = convertElements(expr, {}, replCount);
1137 if (failed(elements))
1140 assert(intType.getWidth() == elements->size());
1141 std::reverse(elements->begin(), elements->end());
1142 return moore::ConcatOp::create(builder, loc, intType, *elements);
1146 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1147 SmallVector<Type> expectedTy;
1148 expectedTy.reserve(structType.getMembers().size());
1149 for (
auto member : structType.getMembers())
1150 expectedTy.push_back(member.type);
1152 FailureOr<SmallVector<Value>> elements;
1153 if (expectedTy.size() == elts.size())
1154 elements = convertElements(expr, expectedTy, replCount);
1156 elements = convertElements(expr, {}, replCount);
1158 if (failed(elements))
1161 assert(structType.getMembers().size() == elements->size());
1162 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1166 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1167 SmallVector<Type> expectedTy;
1168 expectedTy.reserve(structType.getMembers().size());
1169 for (
auto member : structType.getMembers())
1170 expectedTy.push_back(member.type);
1172 FailureOr<SmallVector<Value>> elements;
1173 if (expectedTy.size() == elts.size())
1174 elements = convertElements(expr, expectedTy, replCount);
1176 elements = convertElements(expr, {}, replCount);
1178 if (failed(elements))
1181 assert(structType.getMembers().size() == elements->size());
1183 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1187 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
1189 convertElements(expr, arrayType.getElementType(), replCount);
1191 if (failed(elements))
1194 assert(arrayType.getSize() == elements->size());
1195 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1199 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
1201 convertElements(expr, arrayType.getElementType(), replCount);
1203 if (failed(elements))
1206 assert(arrayType.getSize() == elements->size());
1207 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1210 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
1214 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
1215 return visitAssignmentPattern(expr);
1218 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
1219 return visitAssignmentPattern(expr);
1222 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
1225 assert(count &&
"Slang guarantees constant non-zero replication count");
1226 return visitAssignmentPattern(expr, *count);
1229 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1230 SmallVector<Value> operands;
1231 for (
auto stream : expr.streams()) {
1232 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1233 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1234 mlir::emitError(operandLoc)
1235 <<
"Moore only support streaming "
1236 "concatenation with fixed size 'with expression'";
1240 if (stream.constantWithWidth.has_value()) {
1242 auto type = cast<moore::UnpackedType>(value.getType());
1243 auto intType = moore::IntType::get(
1244 context.
getContext(), type.getBitSize().value(), type.getDomain());
1254 operands.push_back(value);
1258 if (operands.size() == 1) {
1261 value = operands.front();
1263 value = moore::ConcatOp::create(builder, loc, operands).getResult();
1266 if (expr.getSliceSize() == 0) {
1270 auto type = cast<moore::IntType>(value.getType());
1271 SmallVector<Value> slicedOperands;
1272 auto iterMax = type.getWidth() / expr.getSliceSize();
1273 auto remainSize = type.getWidth() % expr.getSliceSize();
1275 for (
size_t i = 0; i < iterMax; i++) {
1276 auto extractResultType = moore::IntType::get(
1277 context.
getContext(), expr.getSliceSize(), type.getDomain());
1279 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
1280 value, i * expr.getSliceSize());
1281 slicedOperands.push_back(extracted);
1285 auto extractResultType = moore::IntType::get(
1286 context.
getContext(), remainSize, type.getDomain());
1289 moore::ExtractOp::create(builder, loc, extractResultType, value,
1290 iterMax * expr.getSliceSize());
1291 slicedOperands.push_back(extracted);
1294 return moore::ConcatOp::create(builder, loc, slicedOperands);
1297 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1302 template <
typename T>
1303 Value visit(T &&node) {
1304 mlir::emitError(loc,
"unsupported expression: ")
1305 << slang::ast::toString(node.kind);
1309 Value visitInvalid(
const slang::ast::Expression &expr) {
1310 mlir::emitError(loc,
"invalid expression");
1321struct LvalueExprVisitor :
public ExprVisitor {
1322 LvalueExprVisitor(
Context &context, Location loc)
1323 : ExprVisitor(context, loc, true) {}
1324 using ExprVisitor::visit;
1327 Value visit(
const slang::ast::NamedValueExpression &expr) {
1328 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1330 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
1332 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1337 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1338 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1343 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1344 << expr.symbol.name <<
"`";
1346 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1350 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1351 SmallVector<Value> operands;
1352 for (
auto stream : expr.streams()) {
1353 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1354 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1355 mlir::emitError(operandLoc)
1356 <<
"Moore only support streaming "
1357 "concatenation with fixed size 'with expression'";
1361 if (stream.constantWithWidth.has_value()) {
1363 auto type = cast<moore::UnpackedType>(
1364 cast<moore::RefType>(value.getType()).getNestedType());
1365 auto intType = moore::RefType::get(moore::IntType::get(
1366 context.
getContext(), type.getBitSize().value(), type.getDomain()));
1375 operands.push_back(value);
1378 if (operands.size() == 1) {
1381 value = operands.front();
1383 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
1386 if (expr.getSliceSize() == 0) {
1390 auto type = cast<moore::IntType>(
1391 cast<moore::RefType>(value.getType()).getNestedType());
1392 SmallVector<Value> slicedOperands;
1393 auto widthSum = type.getWidth();
1394 auto domain = type.getDomain();
1395 auto iterMax = widthSum / expr.getSliceSize();
1396 auto remainSize = widthSum % expr.getSliceSize();
1398 for (
size_t i = 0; i < iterMax; i++) {
1399 auto extractResultType = moore::RefType::get(moore::IntType::get(
1400 context.
getContext(), expr.getSliceSize(), domain));
1402 auto extracted = moore::ExtractRefOp::create(
1403 builder, loc, extractResultType, value, i * expr.getSliceSize());
1404 slicedOperands.push_back(extracted);
1408 auto extractResultType = moore::RefType::get(
1409 moore::IntType::get(context.
getContext(), remainSize, domain));
1412 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
1413 iterMax * expr.getSliceSize());
1414 slicedOperands.push_back(extracted);
1417 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
1421 template <
typename T>
1422 Value visit(T &&node) {
1426 Value visitInvalid(
const slang::ast::Expression &expr) {
1427 mlir::emitError(loc,
"invalid expression");
1437Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
1438 Type requiredType) {
1440 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
1441 if (value && requiredType)
1449 return expr.visit(LvalueExprVisitor(*
this, loc));
1457 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
1458 if (type.getBitSize() == 1)
1460 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
1461 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
1462 mlir::emitError(value.getLoc(),
"expression of type ")
1463 << value.getType() <<
" cannot be cast to a boolean";
1469 const slang::ast::Type &astType, Location loc) {
1474 bool typeIsFourValued =
false;
1475 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
1479 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
1480 fvint.hasUnknown() || typeIsFourValued
1483 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
1488 const slang::ConstantValue &constant,
1489 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
1497 if (astType.elementType.isIntegral())
1498 bitWidth = astType.elementType.getBitWidth();
1502 bool typeIsFourValued =
false;
1505 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
1516 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
1518 auto arrType = moore::UnpackedArrayType::get(
1519 getContext(), constant.elements().size(), intType);
1521 llvm::SmallVector<mlir::Value> elemVals;
1522 moore::ConstantOp constOp;
1524 mlir::OpBuilder::InsertionGuard guard(
builder);
1527 for (
auto elem : constant.elements()) {
1529 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
1530 elemVals.push_back(constOp.getResult());
1535 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
1537 return arrayOp.getResult();
1541 const slang::ast::Type &type, Location loc) {
1543 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
1545 if (constant.isInteger())
1553 using slang::ast::EvalFlags;
1554 slang::ast::EvalContext evalContext(
1556 slang::ast::LookupLocation::max),
1557 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
1558 return expr.eval(evalContext);
1567 auto type = moore::IntType::get(
getContext(), 1, domain);
1574 if (isa<moore::IntType>(value.getType()))
1581 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
1582 if (
auto sbvType = packed.getSimpleBitVector())
1585 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
1586 <<
" cannot be cast to a simple bit vector";
1595 if (isa<moore::IntType>(value.getType()))
1598 auto &builder = context.
builder;
1599 auto packedType = cast<moore::PackedType>(value.getType());
1600 auto intType = packedType.getSimpleBitVector();
1605 if (isa<moore::TimeType>(packedType) &&
1607 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
1608 auto scale = moore::ConstantOp::create(builder, loc, intType,
1610 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
1616 if (packedType.containsTimeType()) {
1617 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
1618 <<
" cannot be converted to " << intType
1619 <<
"; contains a time type";
1624 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
1632 Value value, Location loc) {
1633 if (value.getType() == packedType)
1636 auto &builder = context.
builder;
1637 auto intType = cast<moore::IntType>(value.getType());
1642 if (isa<moore::TimeType>(packedType) &&
1644 auto scale = moore::ConstantOp::create(builder, loc, intType,
1646 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
1647 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
1654 mlir::emitError(loc) <<
"unsupported conversion: " << intType
1655 <<
" cannot be converted to " << packedType
1656 <<
"; contains a time type";
1661 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
1667 if (type == value.getType())
1672 auto dstPacked = dyn_cast<moore::PackedType>(type);
1673 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
1674 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
1675 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
1677 if (dstInt && srcInt) {
1685 auto resizedType = moore::IntType::get(
1686 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
1687 if (dstInt.getWidth() < srcInt.getWidth()) {
1688 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
1689 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
1691 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
1693 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
1697 if (dstInt.getDomain() != srcInt.getDomain()) {
1699 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
1701 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
1709 assert(value.getType() == type);
1714 if (isa<moore::StringType>(type) &&
1715 isa<moore::FormatStringType>(value.getType())) {
1716 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
1720 if (isa<moore::FormatStringType>(type) &&
1721 isa<moore::StringType>(value.getType())) {
1722 return builder.createOrFold<moore::FormatStringOp>(loc, value);
1726 if (value.getType() != type)
1727 value = moore::ConversionOp::create(
builder, loc, type, value);
1735 auto systemCallRes =
1736 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
1739 return moore::UrandomBIOp::create(
builder, loc,
nullptr);
1743 return moore::RandomBIOp::create(
builder, loc,
nullptr);
1747 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
1750 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
1753 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
1754 .Default([&]() -> Value {
return {}; });
1755 return systemCallRes();
1760 Location loc, Value value) {
1761 auto systemCallRes =
1762 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
1764 .Case(
"$signed", [&]() {
return value; })
1765 .Case(
"$unsigned", [&]() {
return value; })
1769 [&]() -> FailureOr<Value> {
1773 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
1777 return moore::LnBIOp::create(
builder, loc, value);
1781 return moore::Log10BIOp::create(
builder, loc, value);
1785 return moore::SinBIOp::create(
builder, loc, value);
1789 return moore::CosBIOp::create(
builder, loc, value);
1793 return moore::TanBIOp::create(
builder, loc, value);
1797 return moore::ExpBIOp::create(
builder, loc, value);
1801 return moore::SqrtBIOp::create(
builder, loc, value);
1805 return moore::FloorBIOp::create(
builder, loc, value);
1809 return moore::CeilBIOp::create(
builder, loc, value);
1813 return moore::AsinBIOp::create(
builder, loc, value);
1817 return moore::AcosBIOp::create(
builder, loc, value);
1821 return moore::AtanBIOp::create(
builder, loc, value);
1825 return moore::SinhBIOp::create(
builder, loc, value);
1829 return moore::CoshBIOp::create(
builder, loc, value);
1833 return moore::TanhBIOp::create(
builder, loc, value);
1837 return moore::AsinhBIOp::create(
builder, loc, value);
1841 return moore::AcoshBIOp::create(
builder, loc, value);
1845 return moore::AtanhBIOp::create(
builder, loc, value);
1849 return moore::UrandomBIOp::create(
builder, loc, value);
1853 return moore::RandomBIOp::create(
builder, loc, value);
1855 .Case(
"$realtobits",
1857 return moore::RealtobitsBIOp::create(
builder, loc, value);
1859 .Case(
"$bitstoreal",
1861 return moore::BitstorealBIOp::create(
builder, loc, value);
1863 .Case(
"$shortrealtobits",
1865 return moore::ShortrealtobitsBIOp::create(
builder, loc,
1868 .Case(
"$bitstoshortreal",
1870 return moore::BitstoshortrealBIOp::create(
builder, loc,
1873 .Default([&]() -> Value {
return {}; });
1874 return systemCallRes();
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 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.
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.
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.
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 convertToBool(Value value)
Helper function to convert a value to its "truthy" boolean value.
ValueSymbols valueSymbols
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 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.
FailureOr< Value > convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value)
Convert system function calls only have arity-1.
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.
SmallVector< Value > lvalueStack
A stack of assignment left-hand side values.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.