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);
466 auto one = moore::ConstantOp::create(
467 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
469 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
470 : moore::SubOp::create(builder, loc, preValue, one).getResult();
471 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
478 Value visit(
const slang::ast::UnaryExpression &expr) {
479 using slang::ast::UnaryOperator;
481 if (expr.op == UnaryOperator::Preincrement ||
482 expr.op == UnaryOperator::Predecrement ||
483 expr.op == UnaryOperator::Postincrement ||
484 expr.op == UnaryOperator::Postdecrement)
494 case UnaryOperator::Plus:
497 case UnaryOperator::Minus:
501 return moore::NegOp::create(builder, loc, arg);
503 case UnaryOperator::BitwiseNot:
507 return moore::NotOp::create(builder, loc, arg);
509 case UnaryOperator::BitwiseAnd:
510 return createReduction<moore::ReduceAndOp>(arg,
false);
511 case UnaryOperator::BitwiseOr:
512 return createReduction<moore::ReduceOrOp>(arg,
false);
513 case UnaryOperator::BitwiseXor:
514 return createReduction<moore::ReduceXorOp>(arg,
false);
515 case UnaryOperator::BitwiseNand:
516 return createReduction<moore::ReduceAndOp>(arg,
true);
517 case UnaryOperator::BitwiseNor:
518 return createReduction<moore::ReduceOrOp>(arg,
true);
519 case UnaryOperator::BitwiseXnor:
520 return createReduction<moore::ReduceXorOp>(arg,
true);
522 case UnaryOperator::LogicalNot:
526 return moore::NotOp::create(builder, loc, arg);
528 case UnaryOperator::Preincrement:
529 return createIncrement(arg,
true,
false);
530 case UnaryOperator::Predecrement:
531 return createIncrement(arg,
false,
false);
532 case UnaryOperator::Postincrement:
533 return createIncrement(arg,
true,
true);
534 case UnaryOperator::Postdecrement:
535 return createIncrement(arg,
false,
true);
538 mlir::emitError(loc,
"unsupported unary operator");
544 template <
class ConcreteOp>
545 Value createBinary(Value lhs, Value rhs) {
552 return ConcreteOp::create(builder, loc, lhs, rhs);
556 Value visit(
const slang::ast::BinaryExpression &expr) {
565 Domain domain = Domain::TwoValued;
566 if (expr.type->isFourState() || expr.left().type->isFourState() ||
567 expr.right().type->isFourState())
568 domain = Domain::FourValued;
570 using slang::ast::BinaryOperator;
572 case BinaryOperator::Add:
573 return createBinary<moore::AddOp>(lhs, rhs);
574 case BinaryOperator::Subtract:
575 return createBinary<moore::SubOp>(lhs, rhs);
576 case BinaryOperator::Multiply:
577 return createBinary<moore::MulOp>(lhs, rhs);
578 case BinaryOperator::Divide:
579 if (expr.type->isSigned())
580 return createBinary<moore::DivSOp>(lhs, rhs);
582 return createBinary<moore::DivUOp>(lhs, rhs);
583 case BinaryOperator::Mod:
584 if (expr.type->isSigned())
585 return createBinary<moore::ModSOp>(lhs, rhs);
587 return createBinary<moore::ModUOp>(lhs, rhs);
588 case BinaryOperator::Power: {
594 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
595 if (expr.type->isSigned())
596 return createBinary<moore::PowSOp>(lhs, rhsCast);
598 return createBinary<moore::PowUOp>(lhs, rhsCast);
601 case BinaryOperator::BinaryAnd:
602 return createBinary<moore::AndOp>(lhs, rhs);
603 case BinaryOperator::BinaryOr:
604 return createBinary<moore::OrOp>(lhs, rhs);
605 case BinaryOperator::BinaryXor:
606 return createBinary<moore::XorOp>(lhs, rhs);
607 case BinaryOperator::BinaryXnor: {
608 auto result = createBinary<moore::XorOp>(lhs, rhs);
611 return moore::NotOp::create(builder, loc, result);
614 case BinaryOperator::Equality:
615 if (isa<moore::UnpackedArrayType>(lhs.getType()))
616 return moore::UArrayCmpOp::create(
617 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
618 else if (isa<moore::StringType>(lhs.getType()))
619 return moore::StringCmpOp::create(
620 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
622 return createBinary<moore::EqOp>(lhs, rhs);
623 case BinaryOperator::Inequality:
624 if (isa<moore::UnpackedArrayType>(lhs.getType()))
625 return moore::UArrayCmpOp::create(
626 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
627 else if (isa<moore::StringType>(lhs.getType()))
628 return moore::StringCmpOp::create(
629 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
631 return createBinary<moore::NeOp>(lhs, rhs);
632 case BinaryOperator::CaseEquality:
633 return createBinary<moore::CaseEqOp>(lhs, rhs);
634 case BinaryOperator::CaseInequality:
635 return createBinary<moore::CaseNeOp>(lhs, rhs);
636 case BinaryOperator::WildcardEquality:
637 return createBinary<moore::WildcardEqOp>(lhs, rhs);
638 case BinaryOperator::WildcardInequality:
639 return createBinary<moore::WildcardNeOp>(lhs, rhs);
641 case BinaryOperator::GreaterThanEqual:
642 if (expr.left().type->isSigned())
643 return createBinary<moore::SgeOp>(lhs, rhs);
644 else if (isa<moore::StringType>(lhs.getType()))
645 return moore::StringCmpOp::create(
646 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
648 return createBinary<moore::UgeOp>(lhs, rhs);
649 case BinaryOperator::GreaterThan:
650 if (expr.left().type->isSigned())
651 return createBinary<moore::SgtOp>(lhs, rhs);
652 else if (isa<moore::StringType>(lhs.getType()))
653 return moore::StringCmpOp::create(
654 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
656 return createBinary<moore::UgtOp>(lhs, rhs);
657 case BinaryOperator::LessThanEqual:
658 if (expr.left().type->isSigned())
659 return createBinary<moore::SleOp>(lhs, rhs);
660 else if (isa<moore::StringType>(lhs.getType()))
661 return moore::StringCmpOp::create(
662 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
664 return createBinary<moore::UleOp>(lhs, rhs);
665 case BinaryOperator::LessThan:
666 if (expr.left().type->isSigned())
667 return createBinary<moore::SltOp>(lhs, rhs);
668 else if (isa<moore::StringType>(lhs.getType()))
669 return moore::StringCmpOp::create(
670 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
672 return createBinary<moore::UltOp>(lhs, rhs);
675 case BinaryOperator::LogicalAnd: {
684 return moore::AndOp::create(builder, loc, lhs, rhs);
686 case BinaryOperator::LogicalOr: {
695 return moore::OrOp::create(builder, loc, lhs, rhs);
697 case BinaryOperator::LogicalImplication: {
705 auto notLHS = moore::NotOp::create(builder, loc, lhs);
706 return moore::OrOp::create(builder, loc, notLHS, rhs);
708 case BinaryOperator::LogicalEquivalence: {
716 auto notLHS = moore::NotOp::create(builder, loc, lhs);
717 auto notRHS = moore::NotOp::create(builder, loc, rhs);
718 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
719 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
720 return moore::OrOp::create(builder, loc, both, notBoth);
723 case BinaryOperator::LogicalShiftLeft:
724 return createBinary<moore::ShlOp>(lhs, rhs);
725 case BinaryOperator::LogicalShiftRight:
726 return createBinary<moore::ShrOp>(lhs, rhs);
727 case BinaryOperator::ArithmeticShiftLeft:
728 return createBinary<moore::ShlOp>(lhs, rhs);
729 case BinaryOperator::ArithmeticShiftRight: {
736 if (expr.type->isSigned())
737 return moore::AShrOp::create(builder, loc, lhs, rhs);
738 return moore::ShrOp::create(builder, loc, lhs, rhs);
742 mlir::emitError(loc,
"unsupported binary operator");
747 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
752 Value visit(
const slang::ast::IntegerLiteral &expr) {
757 Value visit(
const slang::ast::TimeLiteral &expr) {
762 double value = std::round(expr.getValue() * scale);
772 static constexpr uint64_t limit =
773 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
775 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
779 return moore::ConstantTimeOp::create(builder, loc,
780 static_cast<uint64_t
>(value));
784 Value visit(
const slang::ast::ReplicationExpression &expr) {
789 return moore::ReplicateOp::create(builder, loc, type, value);
793 Value visit(
const slang::ast::InsideExpression &expr) {
799 SmallVector<Value> conditions;
802 for (
const auto *listExpr : expr.rangeList()) {
806 if (
const auto *openRange =
807 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
813 if (!lowBound || !highBound)
815 Value leftValue, rightValue;
818 if (openRange->left().type->isSigned() ||
819 expr.left().type->isSigned()) {
820 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
822 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
824 if (openRange->right().type->isSigned() ||
825 expr.left().type->isSigned()) {
826 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
828 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
830 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
833 if (!listExpr->type->isIntegral()) {
834 if (listExpr->type->isUnpackedArray()) {
836 loc,
"unpacked arrays in 'inside' expressions not supported");
840 loc,
"only simple bit vectors supported in 'inside' expressions");
848 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
850 conditions.push_back(cond);
854 auto result = conditions.back();
855 conditions.pop_back();
856 while (!conditions.empty()) {
857 result = moore::OrOp::create(builder, loc, conditions.back(), result);
858 conditions.pop_back();
864 Value visit(
const slang::ast::ConditionalExpression &expr) {
868 if (expr.conditions.size() > 1) {
870 <<
"unsupported conditional expression with more than one condition";
873 const auto &cond = expr.conditions[0];
875 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
883 moore::ConditionalOp::create(builder, loc, type, value);
886 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
887 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
889 OpBuilder::InsertionGuard g(builder);
892 builder.setInsertionPointToStart(&trueBlock);
896 moore::YieldOp::create(builder, loc, trueValue);
899 builder.setInsertionPointToStart(&falseBlock);
903 moore::YieldOp::create(builder, loc, falseValue);
905 return conditionalOp.getResult();
909 Value visit(
const slang::ast::CallExpression &expr) {
911 if (expr.thisClass()) {
912 mlir::emitError(loc,
"unsupported class method call");
922 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
927 Value visitCall(
const slang::ast::CallExpression &expr,
928 const slang::ast::SubroutineSymbol *subroutine) {
936 SmallVector<Value> arguments;
937 for (
auto [callArg, declArg] :
938 llvm::zip(expr.arguments(), subroutine->getArguments())) {
942 auto *expr = callArg;
943 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
944 expr = &assign->left();
947 if (declArg->direction == slang::ast::ArgumentDirection::In)
953 arguments.push_back(value);
958 mlir::func::CallOp::create(builder, loc, lowering->op, arguments);
963 if (callOp.getNumResults() == 0)
964 return mlir::UnrealizedConversionCastOp::create(
965 builder, loc, moore::VoidType::get(context.
getContext()),
969 return callOp.getResult(0);
973 Value visitCall(
const slang::ast::CallExpression &expr,
974 const slang::ast::CallExpression::SystemCallInfo &info) {
975 const auto &subroutine = *
info.subroutine;
976 auto args = expr.arguments();
978 if (args.size() == 1) {
989 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
995 Value visit(
const slang::ast::StringLiteral &expr) {
997 return moore::StringConstantOp::create(builder, loc, type, expr.getValue());
1001 Value visit(
const slang::ast::RealLiteral &expr) {
1002 return moore::RealLiteralOp::create(
1003 builder, loc, builder.getF64FloatAttr(expr.getValue()));
1007 Value visitAssignmentPattern(
1008 const slang::ast::AssignmentPatternExpressionBase &expr,
1009 unsigned replCount = 1) {
1013 auto elementCount = expr.elements().size();
1014 SmallVector<Value> elements;
1015 elements.reserve(replCount * elementCount);
1016 for (
auto elementExpr : expr.elements()) {
1020 elements.push_back(value);
1022 for (
unsigned replIdx = 1; replIdx < replCount; ++replIdx)
1023 for (
unsigned elementIdx = 0; elementIdx < elementCount; ++elementIdx)
1024 elements.push_back(elements[elementIdx]);
1027 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1028 assert(intType.getWidth() == elements.size());
1029 std::reverse(elements.begin(), elements.end());
1030 return moore::ConcatOp::create(builder, loc, intType, elements);
1034 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1035 assert(structType.getMembers().size() == elements.size());
1036 return moore::StructCreateOp::create(builder, loc, structType, elements);
1040 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1041 assert(structType.getMembers().size() == elements.size());
1042 return moore::StructCreateOp::create(builder, loc, structType, elements);
1046 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
1047 assert(arrayType.getSize() == elements.size());
1048 return moore::ArrayCreateOp::create(builder, loc, arrayType, elements);
1052 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
1053 assert(arrayType.getSize() == elements.size());
1054 return moore::ArrayCreateOp::create(builder, loc, arrayType, elements);
1057 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
1061 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
1062 return visitAssignmentPattern(expr);
1065 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
1066 return visitAssignmentPattern(expr);
1069 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
1072 assert(count &&
"Slang guarantees constant non-zero replication count");
1073 return visitAssignmentPattern(expr, *count);
1076 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1077 SmallVector<Value> operands;
1078 for (
auto stream : expr.streams()) {
1079 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1080 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1081 mlir::emitError(operandLoc)
1082 <<
"Moore only support streaming "
1083 "concatenation with fixed size 'with expression'";
1087 if (stream.constantWithWidth.has_value()) {
1089 auto type = cast<moore::UnpackedType>(value.getType());
1090 auto intType = moore::IntType::get(
1091 context.
getContext(), type.getBitSize().value(), type.getDomain());
1101 operands.push_back(value);
1105 if (operands.size() == 1) {
1108 value = operands.front();
1110 value = moore::ConcatOp::create(builder, loc, operands).getResult();
1113 if (expr.getSliceSize() == 0) {
1117 auto type = cast<moore::IntType>(value.getType());
1118 SmallVector<Value> slicedOperands;
1119 auto iterMax = type.getWidth() / expr.getSliceSize();
1120 auto remainSize = type.getWidth() % expr.getSliceSize();
1122 for (
size_t i = 0; i < iterMax; i++) {
1123 auto extractResultType = moore::IntType::get(
1124 context.
getContext(), expr.getSliceSize(), type.getDomain());
1126 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
1127 value, i * expr.getSliceSize());
1128 slicedOperands.push_back(extracted);
1132 auto extractResultType = moore::IntType::get(
1133 context.
getContext(), remainSize, type.getDomain());
1136 moore::ExtractOp::create(builder, loc, extractResultType, value,
1137 iterMax * expr.getSliceSize());
1138 slicedOperands.push_back(extracted);
1141 return moore::ConcatOp::create(builder, loc, slicedOperands);
1144 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1149 template <
typename T>
1150 Value visit(T &&node) {
1151 mlir::emitError(loc,
"unsupported expression: ")
1152 << slang::ast::toString(node.kind);
1156 Value visitInvalid(
const slang::ast::Expression &expr) {
1157 mlir::emitError(loc,
"invalid expression");
1168struct LvalueExprVisitor :
public ExprVisitor {
1169 LvalueExprVisitor(
Context &context, Location loc)
1170 : ExprVisitor(context, loc, true) {}
1171 using ExprVisitor::visit;
1174 Value visit(
const slang::ast::NamedValueExpression &expr) {
1175 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1177 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
1179 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1184 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1185 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1190 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1191 << expr.symbol.name <<
"`";
1193 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1197 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1198 SmallVector<Value> operands;
1199 for (
auto stream : expr.streams()) {
1200 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1201 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1202 mlir::emitError(operandLoc)
1203 <<
"Moore only support streaming "
1204 "concatenation with fixed size 'with expression'";
1208 if (stream.constantWithWidth.has_value()) {
1210 auto type = cast<moore::UnpackedType>(
1211 cast<moore::RefType>(value.getType()).getNestedType());
1212 auto intType = moore::RefType::get(moore::IntType::get(
1213 context.
getContext(), type.getBitSize().value(), type.getDomain()));
1222 operands.push_back(value);
1225 if (operands.size() == 1) {
1228 value = operands.front();
1230 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
1233 if (expr.getSliceSize() == 0) {
1237 auto type = cast<moore::IntType>(
1238 cast<moore::RefType>(value.getType()).getNestedType());
1239 SmallVector<Value> slicedOperands;
1240 auto widthSum = type.getWidth();
1241 auto domain = type.getDomain();
1242 auto iterMax = widthSum / expr.getSliceSize();
1243 auto remainSize = widthSum % expr.getSliceSize();
1245 for (
size_t i = 0; i < iterMax; i++) {
1246 auto extractResultType = moore::RefType::get(moore::IntType::get(
1247 context.
getContext(), expr.getSliceSize(), domain));
1249 auto extracted = moore::ExtractRefOp::create(
1250 builder, loc, extractResultType, value, i * expr.getSliceSize());
1251 slicedOperands.push_back(extracted);
1255 auto extractResultType = moore::RefType::get(
1256 moore::IntType::get(context.
getContext(), remainSize, domain));
1259 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
1260 iterMax * expr.getSliceSize());
1261 slicedOperands.push_back(extracted);
1264 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
1268 template <
typename T>
1269 Value visit(T &&node) {
1273 Value visitInvalid(
const slang::ast::Expression &expr) {
1274 mlir::emitError(loc,
"invalid expression");
1284Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
1285 Type requiredType) {
1287 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
1288 if (value && requiredType)
1296 return expr.visit(LvalueExprVisitor(*
this, loc));
1304 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
1305 if (type.getBitSize() == 1)
1307 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
1308 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
1309 mlir::emitError(value.getLoc(),
"expression of type ")
1310 << value.getType() <<
" cannot be cast to a boolean";
1316 const slang::ast::Type &astType, Location loc) {
1321 bool typeIsFourValued =
false;
1322 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
1326 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
1327 fvint.hasUnknown() || typeIsFourValued
1330 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
1335 const slang::ast::Type &type, Location loc) {
1336 if (constant.isInteger())
1343 using slang::ast::EvalFlags;
1344 slang::ast::EvalContext evalContext(
1346 slang::ast::LookupLocation::max),
1347 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
1348 return expr.eval(evalContext);
1357 auto type = moore::IntType::get(
getContext(), 1, domain);
1364 if (isa<moore::IntType>(value.getType()))
1371 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
1372 if (
auto sbvType = packed.getSimpleBitVector())
1375 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
1376 <<
" cannot be cast to a simple bit vector";
1385 if (isa<moore::IntType>(value.getType()))
1388 auto &builder = context.
builder;
1389 auto packedType = cast<moore::PackedType>(value.getType());
1390 auto intType = packedType.getSimpleBitVector();
1395 if (isa<moore::TimeType>(packedType) &&
1397 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
1398 auto scale = moore::ConstantOp::create(builder, loc, intType,
1400 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
1406 if (packedType.containsTimeType()) {
1407 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
1408 <<
" cannot be converted to " << intType
1409 <<
"; contains a time type";
1414 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
1422 Value value, Location loc) {
1423 if (value.getType() == packedType)
1426 auto &builder = context.
builder;
1427 auto intType = cast<moore::IntType>(value.getType());
1432 if (isa<moore::TimeType>(packedType) &&
1434 auto scale = moore::ConstantOp::create(builder, loc, intType,
1436 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
1437 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
1444 mlir::emitError(loc) <<
"unsupported conversion: " << intType
1445 <<
" cannot be converted to " << packedType
1446 <<
"; contains a time type";
1451 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
1457 if (type == value.getType())
1462 auto dstPacked = dyn_cast<moore::PackedType>(type);
1463 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
1464 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
1465 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
1467 if (dstInt && srcInt) {
1475 auto resizedType = moore::IntType::get(
1476 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
1477 if (dstInt.getWidth() < srcInt.getWidth()) {
1478 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
1479 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
1481 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
1483 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
1487 if (dstInt.getDomain() != srcInt.getDomain()) {
1489 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
1491 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
1499 assert(value.getType() == type);
1504 if (value.getType() != type)
1505 value = moore::ConversionOp::create(
builder, loc, type, value);
1511 Location loc, Value value) {
1512 auto systemCallRes =
1513 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
1515 .Case(
"$signed", [&]() {
return value; })
1516 .Case(
"$unsigned", [&]() {
return value; })
1520 [&]() -> FailureOr<Value> {
1524 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
1528 return moore::LnBIOp::create(
builder, loc, value);
1532 return moore::Log10BIOp::create(
builder, loc, value);
1536 return moore::SinBIOp::create(
builder, loc, value);
1540 return moore::CosBIOp::create(
builder, loc, value);
1544 return moore::TanBIOp::create(
builder, loc, value);
1548 return moore::ExpBIOp::create(
builder, loc, value);
1552 return moore::SqrtBIOp::create(
builder, loc, value);
1556 return moore::FloorBIOp::create(
builder, loc, value);
1560 return moore::CeilBIOp::create(
builder, loc, value);
1564 return moore::AsinBIOp::create(
builder, loc, value);
1568 return moore::AcosBIOp::create(
builder, loc, value);
1572 return moore::AtanBIOp::create(
builder, loc, value);
1576 return moore::SinhBIOp::create(
builder, loc, value);
1580 return moore::CoshBIOp::create(
builder, loc, value);
1584 return moore::TanhBIOp::create(
builder, loc, value);
1588 return moore::AsinhBIOp::create(
builder, loc, value);
1592 return moore::AcoshBIOp::create(
builder, loc, value);
1596 return moore::AtanhBIOp::create(
builder, loc, value);
1598 .Default([&]() -> Value {
return {}; });
1599 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.
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
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
Value convertToSimpleBitVector(Value value)
Helper function to convert a value to its simple bit vector representation, if it has one.
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.