10#include "slang/ast/SystemSubroutine.h"
11#include "slang/syntax/AllSyntax.h"
14using namespace ImportVerilog;
19 if (svint.hasUnknown()) {
20 unsigned numWords = svint.getNumWords() / 2;
21 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
22 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
23 return FVInt(APInt(svint.getBitWidth(), value),
24 APInt(svint.getBitWidth(), unknown));
26 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
27 return FVInt(APInt(svint.getBitWidth(), value));
34 const slang::ConstantRange &range) {
35 auto indexType = cast<moore::UnpackedType>(index.getType());
36 auto bw = std::max(llvm::Log2_32_Ceil(std::max(std::abs(range.lower()),
37 std::abs(range.upper()))),
38 indexType.getBitSize().value());
40 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
42 if (range.isLittleEndian()) {
43 if (range.lower() == 0)
47 builder.createOrFold<moore::ConversionOp>(loc, intType, index);
48 Value offset = builder.create<moore::ConstantOp>(
49 loc, intType, range.lower(), range.lower() < 0);
50 return builder.createOrFold<moore::SubOp>(loc, newIndex, offset);
53 if (range.upper() == 0)
54 return builder.createOrFold<moore::NegOp>(loc, index);
57 builder.createOrFold<moore::ConversionOp>(loc, intType, index);
58 Value offset = builder.create<moore::ConstantOp>(
59 loc, intType, range.upper(), range.upper() < 0);
60 return builder.createOrFold<moore::SubOp>(loc, offset, newIndex);
71 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
72 : context(context), loc(loc), builder(context.builder),
79 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
86 Value visit(
const slang::ast::ElementSelectExpression &expr) {
88 auto value = convertLvalueOrRvalueExpression(expr.value());
92 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
93 auto range = expr.value().type->getFixedRange();
94 if (
auto *constValue = expr.selector().constant) {
95 assert(!constValue->hasUnknown());
96 assert(constValue->size() <= 32);
98 auto lowBit = constValue->integer().as<uint32_t>().value();
100 return builder.create<moore::ExtractRefOp>(
101 loc, resultType, value, range.translateIndex(lowBit));
103 return builder.create<moore::ExtractOp>(loc, resultType, value,
104 range.translateIndex(lowBit));
111 return builder.create<moore::DynExtractRefOp>(loc, resultType, value,
114 return builder.create<moore::DynExtractOp>(loc, resultType, value,
119 Value visit(
const slang::ast::RangeSelectExpression &expr) {
121 auto value = convertLvalueOrRvalueExpression(expr.value());
125 std::optional<int32_t> constLeft;
126 std::optional<int32_t> constRight;
127 if (
auto *constant = expr.left().constant)
128 constLeft = constant->integer().as<int32_t>();
129 if (
auto *constant = expr.right().constant)
130 constRight = constant->integer().as<int32_t>();
148 int32_t offsetConst = 0;
149 auto range = expr.value().type->getFixedRange();
151 using slang::ast::RangeSelectionKind;
152 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
157 assert(constRight &&
"constness checked in slang");
158 offsetConst = *constRight;
169 offsetConst = *constLeft;
180 int32_t offsetAdd = 0;
185 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
186 range.isLittleEndian()) {
187 assert(constRight &&
"constness checked in slang");
188 offsetAdd = 1 - *constRight;
194 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
195 !range.isLittleEndian()) {
196 assert(constRight &&
"constness checked in slang");
197 offsetAdd = *constRight - 1;
201 if (offsetAdd != 0) {
203 offsetDyn = builder.create<moore::AddOp>(
205 builder.create<moore::ConstantOp>(
206 loc, cast<moore::IntType>(offsetDyn.getType()), offsetAdd,
209 offsetConst += offsetAdd;
220 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
225 return builder.create<moore::DynExtractRefOp>(loc, resultType, value,
228 return builder.create<moore::DynExtractOp>(loc, resultType, value,
232 offsetConst = range.translateIndex(offsetConst);
234 return builder.create<moore::ExtractRefOp>(loc, resultType, value,
237 return builder.create<moore::ExtractOp>(loc, resultType, value,
244 Value visit(
const slang::ast::ConcatenationExpression &expr) {
245 SmallVector<Value> operands;
246 for (
auto *operand : expr.operands()) {
250 if (operand->type->isVoid())
252 auto value = convertLvalueOrRvalueExpression(*operand);
257 operands.push_back(value);
260 return builder.create<moore::ConcatRefOp>(loc, operands);
262 return builder.create<moore::ConcatOp>(loc, operands);
266 Value visit(
const slang::ast::MemberAccessExpression &expr) {
268 auto valueType = expr.value().type;
269 auto value = convertLvalueOrRvalueExpression(expr.value());
274 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
275 auto memberName = builder.getStringAttr(expr.member.name);
278 if (valueType->isStruct()) {
280 return builder.create<moore::StructExtractRefOp>(loc, resultType,
283 return builder.create<moore::StructExtractOp>(loc, resultType,
288 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
290 return builder.create<moore::UnionExtractRefOp>(loc, resultType,
293 return builder.create<moore::UnionExtractOp>(loc, type, memberName,
297 mlir::emitError(loc,
"expression of type ")
298 << value.getType() <<
" has no member fields";
310struct RvalueExprVisitor :
public ExprVisitor {
311 RvalueExprVisitor(
Context &context, Location loc)
312 : ExprVisitor(context, loc, false) {}
313 using ExprVisitor::visit;
316 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
319 return builder.create<moore::ReadOp>(loc, lvalue);
323 Value visit(
const slang::ast::NamedValueExpression &expr) {
324 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
325 if (isa<moore::RefType>(value.getType())) {
326 auto readOp = builder.create<moore::ReadOp>(loc, value);
329 value = readOp.getResult();
341 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
343 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
348 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
350 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
351 if (isa<moore::RefType>(value.getType())) {
352 auto readOp = builder.create<moore::ReadOp>(hierLoc, value);
355 value = readOp.getResult();
362 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
363 << expr.symbol.name <<
"`";
364 d.attachNote(hierLoc) <<
"no rvalue generated for "
365 << slang::ast::toString(expr.symbol.kind);
370 Value visit(
const slang::ast::ConversionExpression &expr) {
378 Value visit(
const slang::ast::AssignmentExpression &expr) {
385 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
390 if (expr.timingControl) {
392 mlir::emitError(loc,
"delayed assignments not supported");
396 if (expr.isNonBlocking())
397 builder.create<moore::NonBlockingAssignOp>(loc, lhs, rhs);
399 builder.create<moore::BlockingAssignOp>(loc, lhs, rhs);
405 template <
class ConcreteOp>
406 Value createReduction(Value arg,
bool invert) {
410 Value result = builder.create<ConcreteOp>(loc, arg);
412 result = builder.create<moore::NotOp>(loc, result);
417 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
418 auto preValue = builder.create<moore::ReadOp>(loc, arg);
419 auto one = builder.create<moore::ConstantOp>(
420 loc, cast<moore::IntType>(preValue.getType()), 1);
422 isInc ? builder.create<moore::AddOp>(loc, preValue, one).getResult()
423 : builder.create<moore::SubOp>(loc, preValue, one).getResult();
424 builder.create<moore::BlockingAssignOp>(loc, arg, postValue);
431 Value visit(
const slang::ast::UnaryExpression &expr) {
432 using slang::ast::UnaryOperator;
434 if (expr.op == UnaryOperator::Preincrement ||
435 expr.op == UnaryOperator::Predecrement ||
436 expr.op == UnaryOperator::Postincrement ||
437 expr.op == UnaryOperator::Postdecrement)
447 case UnaryOperator::Plus:
450 case UnaryOperator::Minus:
454 return builder.create<moore::NegOp>(loc, arg);
456 case UnaryOperator::BitwiseNot:
460 return builder.create<moore::NotOp>(loc, arg);
462 case UnaryOperator::BitwiseAnd:
463 return createReduction<moore::ReduceAndOp>(arg,
false);
464 case UnaryOperator::BitwiseOr:
465 return createReduction<moore::ReduceOrOp>(arg,
false);
466 case UnaryOperator::BitwiseXor:
467 return createReduction<moore::ReduceXorOp>(arg,
false);
468 case UnaryOperator::BitwiseNand:
469 return createReduction<moore::ReduceAndOp>(arg,
true);
470 case UnaryOperator::BitwiseNor:
471 return createReduction<moore::ReduceOrOp>(arg,
true);
472 case UnaryOperator::BitwiseXnor:
473 return createReduction<moore::ReduceXorOp>(arg,
true);
475 case UnaryOperator::LogicalNot:
479 return builder.create<moore::NotOp>(loc, arg);
481 case UnaryOperator::Preincrement:
482 return createIncrement(arg,
true,
false);
483 case UnaryOperator::Predecrement:
484 return createIncrement(arg,
false,
false);
485 case UnaryOperator::Postincrement:
486 return createIncrement(arg,
true,
true);
487 case UnaryOperator::Postdecrement:
488 return createIncrement(arg,
false,
true);
491 mlir::emitError(loc,
"unsupported unary operator");
497 template <
class ConcreteOp>
498 Value createBinary(Value lhs, Value rhs) {
505 return builder.create<ConcreteOp>(loc, lhs, rhs);
509 Value visit(
const slang::ast::BinaryExpression &expr) {
518 Domain domain = Domain::TwoValued;
519 if (expr.type->isFourState() || expr.left().type->isFourState() ||
520 expr.right().type->isFourState())
521 domain = Domain::FourValued;
523 using slang::ast::BinaryOperator;
525 case BinaryOperator::Add:
526 return createBinary<moore::AddOp>(lhs, rhs);
527 case BinaryOperator::Subtract:
528 return createBinary<moore::SubOp>(lhs, rhs);
529 case BinaryOperator::Multiply:
530 return createBinary<moore::MulOp>(lhs, rhs);
531 case BinaryOperator::Divide:
532 if (expr.type->isSigned())
533 return createBinary<moore::DivSOp>(lhs, rhs);
535 return createBinary<moore::DivUOp>(lhs, rhs);
536 case BinaryOperator::Mod:
537 if (expr.type->isSigned())
538 return createBinary<moore::ModSOp>(lhs, rhs);
540 return createBinary<moore::ModUOp>(lhs, rhs);
541 case BinaryOperator::Power: {
547 builder.create<moore::ConversionOp>(loc, lhs.getType(), rhs);
548 if (expr.type->isSigned())
549 return createBinary<moore::PowSOp>(lhs, rhsCast);
551 return createBinary<moore::PowUOp>(lhs, rhsCast);
554 case BinaryOperator::BinaryAnd:
555 return createBinary<moore::AndOp>(lhs, rhs);
556 case BinaryOperator::BinaryOr:
557 return createBinary<moore::OrOp>(lhs, rhs);
558 case BinaryOperator::BinaryXor:
559 return createBinary<moore::XorOp>(lhs, rhs);
560 case BinaryOperator::BinaryXnor: {
561 auto result = createBinary<moore::XorOp>(lhs, rhs);
564 return builder.create<moore::NotOp>(loc, result);
567 case BinaryOperator::Equality:
568 if (isa<moore::UnpackedArrayType>(lhs.getType()))
569 return builder.create<moore::UArrayCmpOp>(
570 loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
571 else if (isa<moore::StringType>(lhs.getType()))
572 return builder.create<moore::StringCmpOp>(
573 loc, moore::StringCmpPredicate::eq, lhs, rhs);
575 return createBinary<moore::EqOp>(lhs, rhs);
576 case BinaryOperator::Inequality:
577 if (isa<moore::UnpackedArrayType>(lhs.getType()))
578 return builder.create<moore::UArrayCmpOp>(
579 loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
580 else if (isa<moore::StringType>(lhs.getType()))
581 return builder.create<moore::StringCmpOp>(
582 loc, moore::StringCmpPredicate::ne, lhs, rhs);
584 return createBinary<moore::NeOp>(lhs, rhs);
585 case BinaryOperator::CaseEquality:
586 return createBinary<moore::CaseEqOp>(lhs, rhs);
587 case BinaryOperator::CaseInequality:
588 return createBinary<moore::CaseNeOp>(lhs, rhs);
589 case BinaryOperator::WildcardEquality:
590 return createBinary<moore::WildcardEqOp>(lhs, rhs);
591 case BinaryOperator::WildcardInequality:
592 return createBinary<moore::WildcardNeOp>(lhs, rhs);
594 case BinaryOperator::GreaterThanEqual:
595 if (expr.left().type->isSigned())
596 return createBinary<moore::SgeOp>(lhs, rhs);
597 else if (isa<moore::StringType>(lhs.getType()))
598 return builder.create<moore::StringCmpOp>(
599 loc, moore::StringCmpPredicate::ge, lhs, rhs);
601 return createBinary<moore::UgeOp>(lhs, rhs);
602 case BinaryOperator::GreaterThan:
603 if (expr.left().type->isSigned())
604 return createBinary<moore::SgtOp>(lhs, rhs);
605 else if (isa<moore::StringType>(lhs.getType()))
606 return builder.create<moore::StringCmpOp>(
607 loc, moore::StringCmpPredicate::gt, lhs, rhs);
609 return createBinary<moore::UgtOp>(lhs, rhs);
610 case BinaryOperator::LessThanEqual:
611 if (expr.left().type->isSigned())
612 return createBinary<moore::SleOp>(lhs, rhs);
613 else if (isa<moore::StringType>(lhs.getType()))
614 return builder.create<moore::StringCmpOp>(
615 loc, moore::StringCmpPredicate::le, lhs, rhs);
617 return createBinary<moore::UleOp>(lhs, rhs);
618 case BinaryOperator::LessThan:
619 if (expr.left().type->isSigned())
620 return createBinary<moore::SltOp>(lhs, rhs);
621 else if (isa<moore::StringType>(lhs.getType()))
622 return builder.create<moore::StringCmpOp>(
623 loc, moore::StringCmpPredicate::lt, lhs, rhs);
625 return createBinary<moore::UltOp>(lhs, rhs);
628 case BinaryOperator::LogicalAnd: {
637 return builder.create<moore::AndOp>(loc, lhs, rhs);
639 case BinaryOperator::LogicalOr: {
648 return builder.create<moore::OrOp>(loc, lhs, rhs);
650 case BinaryOperator::LogicalImplication: {
658 auto notLHS = builder.create<moore::NotOp>(loc, lhs);
659 return builder.create<moore::OrOp>(loc, notLHS, rhs);
661 case BinaryOperator::LogicalEquivalence: {
669 auto notLHS = builder.create<moore::NotOp>(loc, lhs);
670 auto notRHS = builder.create<moore::NotOp>(loc, rhs);
671 auto both = builder.create<moore::AndOp>(loc, lhs, rhs);
672 auto notBoth = builder.create<moore::AndOp>(loc, notLHS, notRHS);
673 return builder.create<moore::OrOp>(loc, both, notBoth);
676 case BinaryOperator::LogicalShiftLeft:
677 return createBinary<moore::ShlOp>(lhs, rhs);
678 case BinaryOperator::LogicalShiftRight:
679 return createBinary<moore::ShrOp>(lhs, rhs);
680 case BinaryOperator::ArithmeticShiftLeft:
681 return createBinary<moore::ShlOp>(lhs, rhs);
682 case BinaryOperator::ArithmeticShiftRight: {
689 if (expr.type->isSigned())
690 return builder.create<moore::AShrOp>(loc, lhs, rhs);
691 return builder.create<moore::ShrOp>(loc, lhs, rhs);
695 mlir::emitError(loc,
"unsupported binary operator");
700 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
705 Value visit(
const slang::ast::IntegerLiteral &expr) {
710 Value visit(
const slang::ast::ReplicationExpression &expr) {
715 return builder.create<moore::ReplicateOp>(loc, type, value);
719 Value visit(
const slang::ast::InsideExpression &expr) {
725 SmallVector<Value> conditions;
728 for (
const auto *listExpr : expr.rangeList()) {
732 if (
const auto *openRange =
733 listExpr->as_if<slang::ast::OpenRangeExpression>()) {
739 if (!lowBound || !highBound)
741 Value leftValue, rightValue;
744 if (openRange->left().type->isSigned() ||
745 expr.left().type->isSigned()) {
746 leftValue = builder.create<moore::SgeOp>(loc, lhs, lowBound);
748 leftValue = builder.create<moore::UgeOp>(loc, lhs, lowBound);
750 if (openRange->right().type->isSigned() ||
751 expr.left().type->isSigned()) {
752 rightValue = builder.create<moore::SleOp>(loc, lhs, highBound);
754 rightValue = builder.create<moore::UleOp>(loc, lhs, highBound);
756 cond = builder.create<moore::AndOp>(loc, leftValue, rightValue);
759 if (!listExpr->type->isIntegral()) {
760 if (listExpr->type->isUnpackedArray()) {
762 loc,
"unpacked arrays in 'inside' expressions not supported");
766 loc,
"only simple bit vectors supported in 'inside' expressions");
774 cond = builder.create<moore::WildcardEqOp>(loc, lhs, value);
776 conditions.push_back(cond);
780 auto result = conditions.back();
781 conditions.pop_back();
782 while (!conditions.empty()) {
783 result = builder.create<moore::OrOp>(loc, conditions.back(), result);
784 conditions.pop_back();
790 Value visit(
const slang::ast::ConditionalExpression &expr) {
794 if (expr.conditions.size() > 1) {
796 <<
"unsupported conditional expression with more than one condition";
799 const auto &cond = expr.conditions[0];
801 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
808 auto conditionalOp = builder.create<moore::ConditionalOp>(loc, type, value);
811 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
812 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
814 OpBuilder::InsertionGuard g(builder);
817 builder.setInsertionPointToStart(&trueBlock);
821 builder.create<moore::YieldOp>(loc, trueValue);
824 builder.setInsertionPointToStart(&falseBlock);
828 builder.create<moore::YieldOp>(loc, falseValue);
830 return conditionalOp.getResult();
834 Value visit(
const slang::ast::CallExpression &expr) {
836 if (expr.thisClass()) {
837 mlir::emitError(loc,
"unsupported class method call");
847 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
852 Value visitCall(
const slang::ast::CallExpression &expr,
853 const slang::ast::SubroutineSymbol *subroutine) {
861 SmallVector<Value> arguments;
862 for (
auto [callArg, declArg] :
863 llvm::zip(expr.arguments(), subroutine->getArguments())) {
867 auto *expr = callArg;
868 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
869 expr = &assign->left();
872 if (declArg->direction == slang::ast::ArgumentDirection::In)
878 arguments.push_back(value);
883 builder.create<mlir::func::CallOp>(loc, lowering->op, arguments);
888 if (callOp.getNumResults() == 0)
890 .create<mlir::UnrealizedConversionCastOp>(
891 loc, moore::VoidType::get(context.
getContext()), ValueRange{})
894 return callOp.getResult(0);
898 Value visitCall(
const slang::ast::CallExpression &expr,
899 const slang::ast::CallExpression::SystemCallInfo &info) {
900 const auto &subroutine = *
info.subroutine;
901 auto args = expr.arguments();
903 if (args.size() == 1) {
914 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
920 Value visit(
const slang::ast::StringLiteral &expr) {
922 return builder.create<moore::StringConstantOp>(loc, type, expr.getValue());
926 Value visit(
const slang::ast::RealLiteral &expr) {
927 return builder.create<moore::RealLiteralOp>(
928 loc, builder.getF64FloatAttr(expr.getValue()));
932 Value visitAssignmentPattern(
933 const slang::ast::AssignmentPatternExpressionBase &expr,
934 unsigned replCount = 1) {
938 auto elementCount = expr.elements().size();
939 SmallVector<Value> elements;
940 elements.reserve(replCount * elementCount);
941 for (
auto elementExpr : expr.elements()) {
945 elements.push_back(value);
947 for (
unsigned replIdx = 1; replIdx < replCount; ++replIdx)
948 for (
unsigned elementIdx = 0; elementIdx < elementCount; ++elementIdx)
949 elements.push_back(elements[elementIdx]);
952 if (
auto intType = dyn_cast<moore::IntType>(type)) {
953 assert(intType.getWidth() == elements.size());
954 std::reverse(elements.begin(), elements.end());
955 return builder.create<moore::ConcatOp>(loc, intType, elements);
959 if (
auto structType = dyn_cast<moore::StructType>(type)) {
960 assert(structType.getMembers().size() == elements.size());
961 return builder.create<moore::StructCreateOp>(loc, structType, elements);
965 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
966 assert(structType.getMembers().size() == elements.size());
967 return builder.create<moore::StructCreateOp>(loc, structType, elements);
971 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
972 assert(arrayType.getSize() == elements.size());
973 return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
977 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
978 assert(arrayType.getSize() == elements.size());
979 return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
982 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
986 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
987 return visitAssignmentPattern(expr);
990 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
991 return visitAssignmentPattern(expr);
994 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
997 assert(count &&
"Slang guarantees constant non-zero replication count");
998 return visitAssignmentPattern(expr, *count);
1001 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1002 SmallVector<Value> operands;
1003 for (
auto stream : expr.streams()) {
1004 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1005 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1006 mlir::emitError(operandLoc)
1007 <<
"Moore only support streaming "
1008 "concatenation with fixed size 'with expression'";
1012 if (stream.constantWithWidth.has_value()) {
1014 auto type = cast<moore::UnpackedType>(value.getType());
1015 auto intType = moore::IntType::get(
1016 context.
getContext(), type.getBitSize().value(), type.getDomain());
1026 operands.push_back(value);
1030 if (operands.size() == 1) {
1033 value = operands.front();
1035 value = builder.create<moore::ConcatOp>(loc, operands).getResult();
1038 if (expr.sliceSize == 0) {
1042 auto type = cast<moore::IntType>(value.getType());
1043 SmallVector<Value> slicedOperands;
1044 auto iterMax = type.getWidth() / expr.sliceSize;
1045 auto remainSize = type.getWidth() % expr.sliceSize;
1047 for (
size_t i = 0; i < iterMax; i++) {
1048 auto extractResultType = moore::IntType::get(
1049 context.
getContext(), expr.sliceSize, type.getDomain());
1051 auto extracted = builder.create<moore::ExtractOp>(
1052 loc, extractResultType, value, i * expr.sliceSize);
1053 slicedOperands.push_back(extracted);
1057 auto extractResultType = moore::IntType::get(
1058 context.
getContext(), remainSize, type.getDomain());
1060 auto extracted = builder.create<moore::ExtractOp>(
1061 loc, extractResultType, value, iterMax * expr.sliceSize);
1062 slicedOperands.push_back(extracted);
1065 return builder.create<moore::ConcatOp>(loc, slicedOperands);
1068 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1073 template <
typename T>
1074 Value visit(T &&node) {
1075 mlir::emitError(loc,
"unsupported expression: ")
1076 << slang::ast::toString(node.kind);
1080 Value visitInvalid(
const slang::ast::Expression &expr) {
1081 mlir::emitError(loc,
"invalid expression");
1092struct LvalueExprVisitor :
public ExprVisitor {
1093 LvalueExprVisitor(
Context &context, Location loc)
1094 : ExprVisitor(context, loc, true) {}
1095 using ExprVisitor::visit;
1098 Value visit(
const slang::ast::NamedValueExpression &expr) {
1099 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1101 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
1103 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1108 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1109 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
1114 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1115 << expr.symbol.name <<
"`";
1117 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1121 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1122 SmallVector<Value> operands;
1123 for (
auto stream : expr.streams()) {
1124 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1125 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1126 mlir::emitError(operandLoc)
1127 <<
"Moore only support streaming "
1128 "concatenation with fixed size 'with expression'";
1132 if (stream.constantWithWidth.has_value()) {
1134 auto type = cast<moore::UnpackedType>(
1135 cast<moore::RefType>(value.getType()).getNestedType());
1136 auto intType = moore::RefType::get(moore::IntType::get(
1137 context.
getContext(), type.getBitSize().value(), type.getDomain()));
1146 operands.push_back(value);
1149 if (operands.size() == 1) {
1152 value = operands.front();
1154 value = builder.create<moore::ConcatRefOp>(loc, operands).getResult();
1157 if (expr.sliceSize == 0) {
1161 auto type = cast<moore::IntType>(
1162 cast<moore::RefType>(value.getType()).getNestedType());
1163 SmallVector<Value> slicedOperands;
1164 auto widthSum = type.getWidth();
1165 auto domain = type.getDomain();
1166 auto iterMax = widthSum / expr.sliceSize;
1167 auto remainSize = widthSum % expr.sliceSize;
1169 for (
size_t i = 0; i < iterMax; i++) {
1170 auto extractResultType = moore::RefType::get(
1171 moore::IntType::get(context.
getContext(), expr.sliceSize, domain));
1173 auto extracted = builder.create<moore::ExtractRefOp>(
1174 loc, extractResultType, value, i * expr.sliceSize);
1175 slicedOperands.push_back(extracted);
1179 auto extractResultType = moore::RefType::get(
1180 moore::IntType::get(context.
getContext(), remainSize, domain));
1182 auto extracted = builder.create<moore::ExtractRefOp>(
1183 loc, extractResultType, value, iterMax * expr.sliceSize);
1184 slicedOperands.push_back(extracted);
1187 return builder.create<moore::ConcatRefOp>(loc, slicedOperands);
1191 template <
typename T>
1192 Value visit(T &&node) {
1196 Value visitInvalid(
const slang::ast::Expression &expr) {
1197 mlir::emitError(loc,
"invalid expression");
1207Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
1208 Type requiredType) {
1210 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
1211 if (value && requiredType)
1207Value Context::convertRvalueExpression(
const slang::ast::Expression &expr, {
…}
1219 return expr.visit(LvalueExprVisitor(*
this, loc));
1227 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
1228 if (type.getBitSize() == 1)
1230 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
1231 return builder.create<moore::BoolCastOp>(value.getLoc(), value);
1232 mlir::emitError(value.getLoc(),
"expression of type ")
1233 << value.getType() <<
" cannot be cast to a boolean";
1239 const slang::ast::Type &astType, Location loc) {
1244 bool typeIsFourValued =
false;
1245 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
1249 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
1250 fvint.hasUnknown() || typeIsFourValued
1253 Value result =
builder.create<moore::ConstantOp>(loc, intType, fvint);
1254 if (result.getType() != type)
1255 result =
builder.create<moore::ConversionOp>(loc, type, result);
1260 const slang::ast::Type &type, Location loc) {
1261 if (constant.isInteger())
1268 using slang::ast::EvalFlags;
1269 slang::ast::EvalContext evalContext(
1270 compilation, EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
1271 return expr.eval(evalContext);
1280 auto type = moore::IntType::get(
getContext(), 1, domain);
1281 if (value.getType() == type)
1283 return builder.create<moore::ConversionOp>(value.getLoc(), type, value);
1289 if (isa<moore::IntType>(value.getType()))
1296 if (
auto packed = dyn_cast<moore::PackedType>(value.getType())) {
1297 if (
auto bits = packed.getBitSize()) {
1299 moore::IntType::get(value.getContext(), *bits, packed.getDomain());
1300 return builder.create<moore::ConversionOp>(value.getLoc(), sbvType,
1305 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
1306 <<
" cannot be cast to a simple bit vector";
1312 if (type == value.getType())
1314 auto dstPacked = dyn_cast<moore::PackedType>(type);
1315 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
1318 if (dstPacked && srcPacked && dstPacked.getBitSize() &&
1319 srcPacked.getBitSize() &&
1320 *dstPacked.getBitSize() != *srcPacked.getBitSize()) {
1321 auto dstWidth = *dstPacked.getBitSize();
1322 auto srcWidth = *srcPacked.getBitSize();
1325 auto srcWidthType = moore::IntType::get(value.getContext(), srcWidth,
1326 srcPacked.getDomain());
1327 if (value.getType() != srcWidthType)
1328 value =
builder.create<moore::ConversionOp>(value.getLoc(), srcWidthType,
1333 auto dstWidthType = moore::IntType::get(value.getContext(), dstWidth,
1334 srcPacked.getDomain());
1335 if (dstWidth < srcWidth) {
1336 value =
builder.create<moore::TruncOp>(loc, dstWidthType, value);
1337 }
else if (dstWidth > srcWidth) {
1339 value =
builder.create<moore::SExtOp>(loc, dstWidthType, value);
1341 value =
builder.create<moore::ZExtOp>(loc, dstWidthType, value);
1345 if (value.getType() != type)
1346 value =
builder.create<moore::ConversionOp>(loc, type, value);
1352 Location loc, Value value) {
1353 auto systemCallRes =
1354 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
1356 .Case(
"$signed", [&]() {
return value; })
1357 .Case(
"$unsigned", [&]() {
return value; })
1361 [&]() -> FailureOr<Value> {
1365 return (Value)
builder.create<moore::Clog2BIOp>(loc, value);
1369 return builder.create<moore::LnBIOp>(loc, value);
1373 return builder.create<moore::Log10BIOp>(loc, value);
1377 return builder.create<moore::SinBIOp>(loc, value);
1381 return builder.create<moore::CosBIOp>(loc, value);
1385 return builder.create<moore::TanBIOp>(loc, value);
1389 return builder.create<moore::ExpBIOp>(loc, value);
1393 return builder.create<moore::SqrtBIOp>(loc, value);
1397 return builder.create<moore::FloorBIOp>(loc, value);
1401 return builder.create<moore::CeilBIOp>(loc, value);
1405 return builder.create<moore::AsinBIOp>(loc, value);
1409 return builder.create<moore::AcosBIOp>(loc, value);
1413 return builder.create<moore::AtanBIOp>(loc, value);
1417 return builder.create<moore::SinhBIOp>(loc, value);
1421 return builder.create<moore::CoshBIOp>(loc, value);
1425 return builder.create<moore::TanhBIOp>(loc, value);
1429 return builder.create<moore::AsinhBIOp>(loc, value);
1433 return builder.create<moore::AcoshBIOp>(loc, value);
1437 return builder.create<moore::AtanhBIOp>(loc, value);
1439 .Default([&]() -> Value {
return {}; });
1440 return systemCallRes();
assert(baseType &&"element must be base type")
static Value getSelectIndex(OpBuilder &builder, 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.
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.
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.
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.