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));
32struct RvalueExprVisitor {
37 RvalueExprVisitor(
Context &context, Location loc)
38 : context(context), loc(loc), builder(context.builder) {}
41 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
44 return builder.create<moore::ReadOp>(loc, lvalue);
48 Value visit(
const slang::ast::NamedValueExpression &expr) {
49 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
50 if (isa<moore::RefType>(value.getType())) {
51 auto readOp = builder.create<moore::ReadOp>(loc, value);
54 value = readOp.getResult();
66 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
68 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
73 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
75 if (
auto value = context.
valueSymbols.lookup(&expr.symbol)) {
76 if (isa<moore::RefType>(value.getType())) {
77 auto readOp = builder.create<moore::ReadOp>(hierLoc, value);
80 value = readOp.getResult();
87 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
88 << expr.symbol.name <<
"`";
89 d.attachNote(hierLoc) <<
"no rvalue generated for "
90 << slang::ast::toString(expr.symbol.kind);
95 Value visit(
const slang::ast::ConversionExpression &expr) {
103 Value visit(
const slang::ast::AssignmentExpression &expr) {
110 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
115 if (expr.timingControl) {
117 mlir::emitError(loc,
"delayed assignments not supported");
121 if (expr.isNonBlocking())
122 builder.create<moore::NonBlockingAssignOp>(loc, lhs, rhs);
124 builder.create<moore::BlockingAssignOp>(loc, lhs, rhs);
130 template <
class ConcreteOp>
131 Value createReduction(Value arg,
bool invert) {
135 Value result = builder.create<ConcreteOp>(loc, arg);
137 result = builder.create<moore::NotOp>(loc, result);
142 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
143 auto preValue = builder.create<moore::ReadOp>(loc, arg);
144 auto one = builder.create<moore::ConstantOp>(
145 loc, cast<moore::IntType>(preValue.getType()), 1);
147 isInc ? builder.create<moore::AddOp>(loc, preValue, one).getResult()
148 : builder.create<moore::SubOp>(loc, preValue, one).getResult();
149 builder.create<moore::BlockingAssignOp>(loc, arg, postValue);
156 Value visit(
const slang::ast::UnaryExpression &expr) {
157 using slang::ast::UnaryOperator;
159 if (expr.op == UnaryOperator::Preincrement ||
160 expr.op == UnaryOperator::Predecrement ||
161 expr.op == UnaryOperator::Postincrement ||
162 expr.op == UnaryOperator::Postdecrement)
172 case UnaryOperator::Plus:
175 case UnaryOperator::Minus:
179 return builder.create<moore::NegOp>(loc, arg);
181 case UnaryOperator::BitwiseNot:
185 return builder.create<moore::NotOp>(loc, arg);
187 case UnaryOperator::BitwiseAnd:
188 return createReduction<moore::ReduceAndOp>(arg,
false);
189 case UnaryOperator::BitwiseOr:
190 return createReduction<moore::ReduceOrOp>(arg,
false);
191 case UnaryOperator::BitwiseXor:
192 return createReduction<moore::ReduceXorOp>(arg,
false);
193 case UnaryOperator::BitwiseNand:
194 return createReduction<moore::ReduceAndOp>(arg,
true);
195 case UnaryOperator::BitwiseNor:
196 return createReduction<moore::ReduceOrOp>(arg,
true);
197 case UnaryOperator::BitwiseXnor:
198 return createReduction<moore::ReduceXorOp>(arg,
true);
200 case UnaryOperator::LogicalNot:
204 return builder.create<moore::NotOp>(loc, arg);
206 case UnaryOperator::Preincrement:
207 return createIncrement(arg,
true,
false);
208 case UnaryOperator::Predecrement:
209 return createIncrement(arg,
false,
false);
210 case UnaryOperator::Postincrement:
211 return createIncrement(arg,
true,
true);
212 case UnaryOperator::Postdecrement:
213 return createIncrement(arg,
false,
true);
216 mlir::emitError(loc,
"unsupported unary operator");
222 template <
class ConcreteOp>
223 Value createBinary(Value lhs, Value rhs) {
230 return builder.create<ConcreteOp>(loc, lhs, rhs);
234 Value visit(
const slang::ast::BinaryExpression &expr) {
243 Domain domain = Domain::TwoValued;
244 if (expr.type->isFourState() || expr.left().type->isFourState() ||
245 expr.right().type->isFourState())
246 domain = Domain::FourValued;
248 using slang::ast::BinaryOperator;
250 case BinaryOperator::Add:
251 return createBinary<moore::AddOp>(lhs, rhs);
252 case BinaryOperator::Subtract:
253 return createBinary<moore::SubOp>(lhs, rhs);
254 case BinaryOperator::Multiply:
255 return createBinary<moore::MulOp>(lhs, rhs);
256 case BinaryOperator::Divide:
257 if (expr.type->isSigned())
258 return createBinary<moore::DivSOp>(lhs, rhs);
260 return createBinary<moore::DivUOp>(lhs, rhs);
261 case BinaryOperator::Mod:
262 if (expr.type->isSigned())
263 return createBinary<moore::ModSOp>(lhs, rhs);
265 return createBinary<moore::ModUOp>(lhs, rhs);
266 case BinaryOperator::Power: {
272 builder.create<moore::ConversionOp>(loc, lhs.getType(), rhs);
273 if (expr.type->isSigned())
274 return createBinary<moore::PowSOp>(lhs, rhsCast);
276 return createBinary<moore::PowUOp>(lhs, rhsCast);
279 case BinaryOperator::BinaryAnd:
280 return createBinary<moore::AndOp>(lhs, rhs);
281 case BinaryOperator::BinaryOr:
282 return createBinary<moore::OrOp>(lhs, rhs);
283 case BinaryOperator::BinaryXor:
284 return createBinary<moore::XorOp>(lhs, rhs);
285 case BinaryOperator::BinaryXnor: {
286 auto result = createBinary<moore::XorOp>(lhs, rhs);
289 return builder.create<moore::NotOp>(loc, result);
292 case BinaryOperator::Equality:
293 if (isa<moore::UnpackedArrayType>(lhs.getType()))
294 return builder.create<moore::UArrayCmpOp>(
295 loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
296 else if (isa<moore::StringType>(lhs.getType()))
297 return builder.create<moore::StringCmpOp>(
298 loc, moore::StringCmpPredicate::eq, lhs, rhs);
300 return createBinary<moore::EqOp>(lhs, rhs);
301 case BinaryOperator::Inequality:
302 if (isa<moore::UnpackedArrayType>(lhs.getType()))
303 return builder.create<moore::UArrayCmpOp>(
304 loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
305 else if (isa<moore::StringType>(lhs.getType()))
306 return builder.create<moore::StringCmpOp>(
307 loc, moore::StringCmpPredicate::ne, lhs, rhs);
309 return createBinary<moore::NeOp>(lhs, rhs);
310 case BinaryOperator::CaseEquality:
311 return createBinary<moore::CaseEqOp>(lhs, rhs);
312 case BinaryOperator::CaseInequality:
313 return createBinary<moore::CaseNeOp>(lhs, rhs);
314 case BinaryOperator::WildcardEquality:
315 return createBinary<moore::WildcardEqOp>(lhs, rhs);
316 case BinaryOperator::WildcardInequality:
317 return createBinary<moore::WildcardNeOp>(lhs, rhs);
319 case BinaryOperator::GreaterThanEqual:
320 if (expr.left().type->isSigned())
321 return createBinary<moore::SgeOp>(lhs, rhs);
322 else if (isa<moore::StringType>(lhs.getType()))
323 return builder.create<moore::StringCmpOp>(
324 loc, moore::StringCmpPredicate::ge, lhs, rhs);
326 return createBinary<moore::UgeOp>(lhs, rhs);
327 case BinaryOperator::GreaterThan:
328 if (expr.left().type->isSigned())
329 return createBinary<moore::SgtOp>(lhs, rhs);
330 else if (isa<moore::StringType>(lhs.getType()))
331 return builder.create<moore::StringCmpOp>(
332 loc, moore::StringCmpPredicate::gt, lhs, rhs);
334 return createBinary<moore::UgtOp>(lhs, rhs);
335 case BinaryOperator::LessThanEqual:
336 if (expr.left().type->isSigned())
337 return createBinary<moore::SleOp>(lhs, rhs);
338 else if (isa<moore::StringType>(lhs.getType()))
339 return builder.create<moore::StringCmpOp>(
340 loc, moore::StringCmpPredicate::le, lhs, rhs);
342 return createBinary<moore::UleOp>(lhs, rhs);
343 case BinaryOperator::LessThan:
344 if (expr.left().type->isSigned())
345 return createBinary<moore::SltOp>(lhs, rhs);
346 else if (isa<moore::StringType>(lhs.getType()))
347 return builder.create<moore::StringCmpOp>(
348 loc, moore::StringCmpPredicate::lt, lhs, rhs);
350 return createBinary<moore::UltOp>(lhs, rhs);
353 case BinaryOperator::LogicalAnd: {
362 return builder.create<moore::AndOp>(loc, lhs, rhs);
364 case BinaryOperator::LogicalOr: {
373 return builder.create<moore::OrOp>(loc, lhs, rhs);
375 case BinaryOperator::LogicalImplication: {
383 auto notLHS = builder.create<moore::NotOp>(loc, lhs);
384 return builder.create<moore::OrOp>(loc, notLHS, rhs);
386 case BinaryOperator::LogicalEquivalence: {
394 auto notLHS = builder.create<moore::NotOp>(loc, lhs);
395 auto notRHS = builder.create<moore::NotOp>(loc, rhs);
396 auto both = builder.create<moore::AndOp>(loc, lhs, rhs);
397 auto notBoth = builder.create<moore::AndOp>(loc, notLHS, notRHS);
398 return builder.create<moore::OrOp>(loc, both, notBoth);
401 case BinaryOperator::LogicalShiftLeft:
402 return createBinary<moore::ShlOp>(lhs, rhs);
403 case BinaryOperator::LogicalShiftRight:
404 return createBinary<moore::ShrOp>(lhs, rhs);
405 case BinaryOperator::ArithmeticShiftLeft:
406 return createBinary<moore::ShlOp>(lhs, rhs);
407 case BinaryOperator::ArithmeticShiftRight: {
414 if (expr.type->isSigned())
415 return builder.create<moore::AShrOp>(loc, lhs, rhs);
416 return builder.create<moore::ShrOp>(loc, lhs, rhs);
420 mlir::emitError(loc,
"unsupported binary operator");
425 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
430 Value visit(
const slang::ast::IntegerLiteral &expr) {
435 Value visit(
const slang::ast::ConcatenationExpression &expr) {
436 SmallVector<Value> operands;
437 for (
auto *operand : expr.operands()) {
441 if (operand->type->isVoid())
447 operands.push_back(value);
449 return builder.create<moore::ConcatOp>(loc, operands);
453 Value visit(
const slang::ast::ReplicationExpression &expr) {
458 return builder.create<moore::ReplicateOp>(loc, type, value);
461 Value getSelectIndex(Value index,
const slang::ConstantRange &range)
const {
462 auto indexType = cast<moore::UnpackedType>(index.getType());
463 auto bw = std::max(llvm::Log2_32_Ceil(std::max(std::abs(range.lower()),
464 std::abs(range.upper()))),
465 indexType.getBitSize().value());
467 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
469 if (range.isLittleEndian()) {
470 if (range.lower() == 0)
474 builder.createOrFold<moore::ConversionOp>(loc, intType, index);
475 Value offset = builder.create<moore::ConstantOp>(
476 loc, intType, range.lower(), range.lower() < 0);
477 return builder.createOrFold<moore::SubOp>(loc, newIndex, offset);
480 if (range.upper() == 0)
481 return builder.createOrFold<moore::NegOp>(loc, index);
484 builder.createOrFold<moore::ConversionOp>(loc, intType, index);
485 Value offset = builder.create<moore::ConstantOp>(
486 loc, intType, range.upper(), range.upper() < 0);
487 return builder.createOrFold<moore::SubOp>(loc, offset, newIndex);
491 Value visit(
const slang::ast::ElementSelectExpression &expr) {
496 auto range = expr.value().type->getFixedRange();
497 if (
auto *constValue = expr.selector().constant) {
498 assert(!constValue->hasUnknown());
499 assert(constValue->size() <= 32);
501 auto lowBit = constValue->integer().as<uint32_t>().value();
502 return builder.create<moore::ExtractOp>(loc, type, value,
503 range.translateIndex(lowBit));
508 return builder.create<moore::DynExtractOp>(loc, type, value,
509 getSelectIndex(lowBit, range));
513 Value visit(
const slang::ast::RangeSelectExpression &expr) {
520 uint32_t constLowBit;
521 auto *leftConst = expr.left().constant;
522 auto *rightConst = expr.right().constant;
524 assert(!leftConst->hasUnknown());
525 assert(leftConst->size() <= 32);
528 assert(!rightConst->hasUnknown());
529 assert(rightConst->size() <= 32);
532 if (expr.getSelectionKind() == slang::ast::RangeSelectionKind::Simple) {
533 if (leftConst && rightConst) {
535 auto lhs = leftConst->integer().as<uint32_t>().value();
536 auto rhs = rightConst->integer().as<uint32_t>().value();
537 constLowBit = lhs < rhs ? lhs : rhs;
539 mlir::emitError(loc,
"unsupported a variable as the index in the")
540 << slang::ast::toString(expr.getSelectionKind()) <<
"kind";
543 }
else if (expr.getSelectionKind() ==
544 slang::ast::RangeSelectionKind::IndexedDown) {
549 auto subtrahend = leftConst->integer().as<uint32_t>().value();
551 expr.right().constant->integer().as<uint32_t>().value();
552 constLowBit = subtrahend - sliceWidth - 1;
555 auto subtrahendType = cast<moore::UnpackedType>(subtrahend.getType());
556 auto intType = moore::IntType::get(context.
getContext(),
557 subtrahendType.getBitSize().value(),
558 subtrahendType.getDomain());
560 expr.right().constant->integer().as<uint32_t>().value() - 1;
561 auto minuend = builder.create<moore::ConstantOp>(
562 loc, intType, sliceWidth, expr.left().type->isSigned());
563 dynLowBit = builder.create<moore::SubOp>(loc, subtrahend, minuend);
568 constLowBit = leftConst->integer().as<uint32_t>().value();
572 auto range = expr.value().type->getFixedRange();
573 if (leftConst && rightConst)
574 return builder.create<moore::ExtractOp>(
575 loc, type, value, range.translateIndex(constLowBit));
576 return builder.create<moore::DynExtractOp>(
577 loc, type, value, getSelectIndex(dynLowBit, range));
580 Value visit(
const slang::ast::MemberAccessExpression &expr) {
582 auto valueType = expr.value().type;
586 if (valueType->isStruct()) {
587 return builder.create<moore::StructExtractOp>(
588 loc, type, builder.getStringAttr(expr.member.name), value);
590 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
591 return builder.create<moore::UnionExtractOp>(
592 loc, type, builder.getStringAttr(expr.member.name), value);
594 mlir::emitError(loc,
"expression of type ")
595 << value.getType() <<
" cannot be accessed";
600 Value visit(
const slang::ast::InsideExpression &expr) {
606 SmallVector<Value> conditions;
609 for (
const auto *listExpr : expr.rangeList()) {
613 if (
const auto *openRange =
614 listExpr->as_if<slang::ast::OpenRangeExpression>()) {
620 if (!lowBound || !highBound)
622 Value leftValue, rightValue;
625 if (openRange->left().type->isSigned() ||
626 expr.left().type->isSigned()) {
627 leftValue = builder.create<moore::SgeOp>(loc, lhs, lowBound);
629 leftValue = builder.create<moore::UgeOp>(loc, lhs, lowBound);
631 if (openRange->right().type->isSigned() ||
632 expr.left().type->isSigned()) {
633 rightValue = builder.create<moore::SleOp>(loc, lhs, highBound);
635 rightValue = builder.create<moore::UleOp>(loc, lhs, highBound);
637 cond = builder.create<moore::AndOp>(loc, leftValue, rightValue);
640 if (!listExpr->type->isSimpleBitVector()) {
641 if (listExpr->type->isUnpackedArray()) {
643 loc,
"unpacked arrays in 'inside' expressions not supported");
647 loc,
"only simple bit vectors supported in 'inside' expressions");
654 cond = builder.create<moore::WildcardEqOp>(loc, lhs, value);
656 conditions.push_back(cond);
660 auto result = conditions.back();
661 conditions.pop_back();
662 while (!conditions.empty()) {
663 result = builder.create<moore::OrOp>(loc, conditions.back(), result);
664 conditions.pop_back();
670 Value visit(
const slang::ast::ConditionalExpression &expr) {
674 if (expr.conditions.size() > 1) {
676 <<
"unsupported conditional expression with more than one condition";
679 const auto &cond = expr.conditions[0];
681 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
688 auto conditionalOp = builder.create<moore::ConditionalOp>(loc, type, value);
691 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
692 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
694 OpBuilder::InsertionGuard g(builder);
697 builder.setInsertionPointToStart(&trueBlock);
701 builder.create<moore::YieldOp>(loc, trueValue);
704 builder.setInsertionPointToStart(&falseBlock);
708 builder.create<moore::YieldOp>(loc, falseValue);
710 return conditionalOp.getResult();
714 Value visit(
const slang::ast::CallExpression &expr) {
716 if (expr.thisClass()) {
717 mlir::emitError(loc,
"unsupported class method call");
727 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
732 Value visitCall(
const slang::ast::CallExpression &expr,
733 const slang::ast::SubroutineSymbol *subroutine) {
741 SmallVector<Value> arguments;
742 for (
auto [callArg, declArg] :
743 llvm::zip(expr.arguments(), subroutine->getArguments())) {
747 auto *expr = callArg;
748 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
749 expr = &assign->left();
752 if (declArg->direction == slang::ast::ArgumentDirection::In)
758 arguments.push_back(value);
763 builder.create<mlir::func::CallOp>(loc, lowering->op, arguments);
768 if (callOp.getNumResults() == 0)
770 .create<mlir::UnrealizedConversionCastOp>(
771 loc, moore::VoidType::get(context.
getContext()), ValueRange{})
774 return callOp.getResult(0);
778 Value visitCall(
const slang::ast::CallExpression &expr,
779 const slang::ast::CallExpression::SystemCallInfo &info) {
780 const auto &subroutine = *
info.subroutine;
781 auto args = expr.arguments();
783 if (args.size() == 1) {
794 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
800 Value visit(
const slang::ast::StringLiteral &expr) {
802 return builder.create<moore::StringConstantOp>(loc, type, expr.getValue());
806 Value visit(
const slang::ast::RealLiteral &expr) {
807 return builder.create<moore::RealLiteralOp>(
808 loc, builder.getF64FloatAttr(expr.getValue()));
812 Value visitAssignmentPattern(
813 const slang::ast::AssignmentPatternExpressionBase &expr,
814 unsigned replCount = 1) {
818 auto elementCount = expr.elements().size();
819 SmallVector<Value> elements;
820 elements.reserve(replCount * elementCount);
821 for (
auto elementExpr : expr.elements()) {
825 elements.push_back(value);
827 for (
unsigned replIdx = 1; replIdx < replCount; ++replIdx)
828 for (
unsigned elementIdx = 0; elementIdx < elementCount; ++elementIdx)
829 elements.push_back(elements[elementIdx]);
832 if (
auto intType = dyn_cast<moore::IntType>(type)) {
833 assert(intType.getWidth() == elements.size());
834 std::reverse(elements.begin(), elements.end());
835 return builder.create<moore::ConcatOp>(loc, intType, elements);
839 if (
auto structType = dyn_cast<moore::StructType>(type)) {
840 assert(structType.getMembers().size() == elements.size());
841 return builder.create<moore::StructCreateOp>(loc, structType, elements);
845 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
846 assert(structType.getMembers().size() == elements.size());
847 return builder.create<moore::StructCreateOp>(loc, structType, elements);
851 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
852 assert(arrayType.getSize() == elements.size());
853 return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
857 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
858 assert(arrayType.getSize() == elements.size());
859 return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
862 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
866 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
867 return visitAssignmentPattern(expr);
870 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
871 return visitAssignmentPattern(expr);
874 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
877 assert(count &&
"Slang guarantees constant non-zero replication count");
878 return visitAssignmentPattern(expr, *count);
881 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
882 SmallVector<Value> operands;
883 for (
auto stream : expr.streams()) {
884 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
885 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
886 mlir::emitError(operandLoc)
887 <<
"Moore only support streaming "
888 "concatenation with fixed size 'with expression'";
892 if (stream.constantWithWidth.has_value()) {
894 auto type = cast<moore::UnpackedType>(value.getType());
895 auto intType = moore::IntType::get(
896 context.
getContext(), type.getBitSize().value(), type.getDomain());
906 operands.push_back(value);
910 if (operands.size() == 1) {
913 value = operands.front();
915 value = builder.create<moore::ConcatOp>(loc, operands).getResult();
918 if (expr.sliceSize == 0) {
922 auto type = cast<moore::IntType>(value.getType());
923 SmallVector<Value> slicedOperands;
924 auto iterMax = type.getWidth() / expr.sliceSize;
925 auto remainSize = type.getWidth() % expr.sliceSize;
927 for (
size_t i = 0; i < iterMax; i++) {
928 auto extractResultType = moore::IntType::get(
929 context.
getContext(), expr.sliceSize, type.getDomain());
931 auto extracted = builder.create<moore::ExtractOp>(
932 loc, extractResultType, value, i * expr.sliceSize);
933 slicedOperands.push_back(extracted);
937 auto extractResultType = moore::IntType::get(
938 context.
getContext(), remainSize, type.getDomain());
940 auto extracted = builder.create<moore::ExtractOp>(
941 loc, extractResultType, value, iterMax * expr.sliceSize);
942 slicedOperands.push_back(extracted);
945 return builder.create<moore::ConcatOp>(loc, slicedOperands);
949 template <
typename T>
950 Value visit(T &&node) {
951 mlir::emitError(loc,
"unsupported expression: ")
952 << slang::ast::toString(node.kind);
956 Value visitInvalid(
const slang::ast::Expression &expr) {
957 mlir::emitError(loc,
"invalid expression");
964struct LvalueExprVisitor {
969 LvalueExprVisitor(
Context &context, Location loc)
970 : context(context), loc(loc), builder(context.builder) {}
973 Value visit(
const slang::ast::NamedValueExpression &expr) {
974 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
976 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
978 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
983 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
984 if (
auto value = context.
valueSymbols.lookup(&expr.symbol))
989 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
990 << expr.symbol.name <<
"`";
992 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
997 Value visit(
const slang::ast::ConcatenationExpression &expr) {
998 SmallVector<Value> operands;
999 for (
auto *operand : expr.operands()) {
1003 operands.push_back(value);
1005 return builder.create<moore::ConcatRefOp>(loc, operands);
1009 Value visit(
const slang::ast::ElementSelectExpression &expr) {
1012 if (!type || !value)
1014 if (
auto *constValue = expr.selector().constant) {
1015 assert(!constValue->hasUnknown());
1016 assert(constValue->size() <= 32);
1018 auto lowBit = constValue->integer().as<uint32_t>().value();
1019 return builder.create<moore::ExtractRefOp>(
1020 loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
1026 return builder.create<moore::DynExtractRefOp>(
1027 loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
1032 Value visit(
const slang::ast::RangeSelectExpression &expr) {
1035 if (!type || !value)
1039 uint32_t constLowBit;
1040 auto *leftConst = expr.left().constant;
1041 auto *rightConst = expr.right().constant;
1043 assert(!leftConst->hasUnknown());
1044 assert(leftConst->size() <= 32);
1047 assert(!rightConst->hasUnknown());
1048 assert(rightConst->size() <= 32);
1051 if (expr.getSelectionKind() == slang::ast::RangeSelectionKind::Simple) {
1052 if (leftConst && rightConst) {
1054 auto lhs = leftConst->integer().as<uint32_t>().value();
1055 auto rhs = rightConst->integer().as<uint32_t>().value();
1056 constLowBit = lhs < rhs ? lhs : rhs;
1058 mlir::emitError(loc,
"unsupported a variable as the index in the")
1059 << slang::ast::toString(expr.getSelectionKind()) <<
"kind";
1062 }
else if (expr.getSelectionKind() ==
1063 slang::ast::RangeSelectionKind::IndexedDown) {
1068 auto subtrahend = leftConst->integer().as<uint32_t>().value();
1070 expr.right().constant->integer().as<uint32_t>().value();
1071 constLowBit = subtrahend - sliceWidth - 1;
1074 auto subtrahendType = cast<moore::UnpackedType>(subtrahend.getType());
1075 auto intType = moore::IntType::get(context.
getContext(),
1076 subtrahendType.getBitSize().value(),
1077 subtrahendType.getDomain());
1079 expr.right().constant->integer().as<uint32_t>().value() - 1;
1081 builder.create<moore::ConstantOp>(loc, intType, sliceWidth);
1082 dynLowBit = builder.create<moore::SubOp>(loc, subtrahend, minuend);
1087 constLowBit = leftConst->integer().as<uint32_t>().value();
1091 if (leftConst && rightConst)
1092 return builder.create<moore::ExtractRefOp>(
1093 loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
1095 return builder.create<moore::DynExtractRefOp>(
1096 loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
1100 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1101 SmallVector<Value> operands;
1102 for (
auto stream : expr.streams()) {
1103 auto operandLoc = context.
convertLocation(stream.operand->sourceRange);
1104 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1105 mlir::emitError(operandLoc)
1106 <<
"Moore only support streaming "
1107 "concatenation with fixed size 'with expression'";
1111 if (stream.constantWithWidth.has_value()) {
1113 auto type = cast<moore::UnpackedType>(
1114 cast<moore::RefType>(value.getType()).getNestedType());
1115 auto intType = moore::RefType::get(moore::IntType::get(
1116 context.
getContext(), type.getBitSize().value(), type.getDomain()));
1125 operands.push_back(value);
1128 if (operands.size() == 1) {
1131 value = operands.front();
1133 value = builder.create<moore::ConcatRefOp>(loc, operands).getResult();
1136 if (expr.sliceSize == 0) {
1140 auto type = cast<moore::IntType>(
1141 cast<moore::RefType>(value.getType()).getNestedType());
1142 SmallVector<Value> slicedOperands;
1143 auto widthSum = type.getWidth();
1144 auto domain = type.getDomain();
1145 auto iterMax = widthSum / expr.sliceSize;
1146 auto remainSize = widthSum % expr.sliceSize;
1148 for (
size_t i = 0; i < iterMax; i++) {
1149 auto extractResultType = moore::RefType::get(
1150 moore::IntType::get(context.
getContext(), expr.sliceSize, domain));
1152 auto extracted = builder.create<moore::ExtractRefOp>(
1153 loc, extractResultType, value, i * expr.sliceSize);
1154 slicedOperands.push_back(extracted);
1158 auto extractResultType = moore::RefType::get(
1159 moore::IntType::get(context.
getContext(), remainSize, domain));
1161 auto extracted = builder.create<moore::ExtractRefOp>(
1162 loc, extractResultType, value, iterMax * expr.sliceSize);
1163 slicedOperands.push_back(extracted);
1166 return builder.create<moore::ConcatRefOp>(loc, slicedOperands);
1169 Value visit(
const slang::ast::MemberAccessExpression &expr) {
1171 auto valueType = expr.value().type;
1173 if (!type || !value)
1175 if (valueType->isStruct()) {
1176 return builder.create<moore::StructExtractRefOp>(
1177 loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
1178 builder.getStringAttr(expr.member.name), value);
1180 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
1181 return builder.create<moore::UnionExtractRefOp>(
1182 loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
1183 builder.getStringAttr(expr.member.name), value);
1185 mlir::emitError(loc,
"expression of type ")
1186 << value.getType() <<
" cannot be accessed";
1191 template <
typename T>
1192 Value visit(T &&node) {
1196 Value visitInvalid(
const slang::ast::Expression &expr) {
1197 mlir::emitError(loc,
"invalid expression");
1204 Type requiredType) {
1206 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
1207 if (value && requiredType)
1215 return expr.visit(LvalueExprVisitor(*
this, loc));
1223 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
1224 if (type.getBitSize() == 1)
1226 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
1227 return builder.create<moore::BoolCastOp>(value.getLoc(), value);
1228 mlir::emitError(value.getLoc(),
"expression of type ")
1229 << value.getType() <<
" cannot be cast to a boolean";
1235 const slang::ast::Type &astType, Location loc) {
1240 bool typeIsFourValued =
false;
1241 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
1245 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
1246 fvint.hasUnknown() || typeIsFourValued
1249 Value result =
builder.create<moore::ConstantOp>(loc, intType, fvint);
1250 if (result.getType() != type)
1251 result =
builder.create<moore::ConversionOp>(loc, type, result);
1256 const slang::ast::Type &type, Location loc) {
1257 if (constant.isInteger())
1264 using slang::ast::EvalFlags;
1265 slang::ast::EvalContext evalContext(
1266 compilation, EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
1267 return expr.eval(evalContext);
1276 auto type = moore::IntType::get(
getContext(), 1, domain);
1277 if (value.getType() == type)
1279 return builder.create<moore::ConversionOp>(value.getLoc(), type, value);
1285 if (isa<moore::IntType>(value.getType()))
1292 if (
auto packed = dyn_cast<moore::PackedType>(value.getType())) {
1293 if (
auto bits = packed.getBitSize()) {
1295 moore::IntType::get(value.getContext(), *bits, packed.getDomain());
1296 return builder.create<moore::ConversionOp>(value.getLoc(), sbvType,
1301 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
1302 <<
" cannot be cast to a simple bit vector";
1308 if (type == value.getType())
1310 auto dstPacked = dyn_cast<moore::PackedType>(type);
1311 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
1314 if (dstPacked && srcPacked && dstPacked.getBitSize() &&
1315 srcPacked.getBitSize() &&
1316 *dstPacked.getBitSize() != *srcPacked.getBitSize()) {
1317 auto dstWidth = *dstPacked.getBitSize();
1318 auto srcWidth = *srcPacked.getBitSize();
1321 auto srcWidthType = moore::IntType::get(value.getContext(), srcWidth,
1322 srcPacked.getDomain());
1323 if (value.getType() != srcWidthType)
1324 value =
builder.create<moore::ConversionOp>(value.getLoc(), srcWidthType,
1329 auto dstWidthType = moore::IntType::get(value.getContext(), dstWidth,
1330 srcPacked.getDomain());
1331 if (dstWidth < srcWidth) {
1332 value =
builder.create<moore::TruncOp>(loc, dstWidthType, value);
1333 }
else if (dstWidth > srcWidth) {
1335 value =
builder.create<moore::SExtOp>(loc, dstWidthType, value);
1337 value =
builder.create<moore::ZExtOp>(loc, dstWidthType, value);
1341 if (value.getType() != type)
1342 value =
builder.create<moore::ConversionOp>(loc, type, value);
1348 Location loc, Value value) {
1349 auto systemCallRes =
1350 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
1352 .Case(
"$signed", [&]() {
return value; })
1353 .Case(
"$unsigned", [&]() {
return value; })
1357 [&]() -> FailureOr<Value> {
1361 return (Value)
builder.create<moore::Clog2BIOp>(loc, value);
1365 return builder.create<moore::LnBIOp>(loc, value);
1369 return builder.create<moore::Log10BIOp>(loc, value);
1373 return builder.create<moore::SinBIOp>(loc, value);
1377 return builder.create<moore::CosBIOp>(loc, value);
1381 return builder.create<moore::TanBIOp>(loc, value);
1385 return builder.create<moore::ExpBIOp>(loc, value);
1389 return builder.create<moore::SqrtBIOp>(loc, value);
1393 return builder.create<moore::FloorBIOp>(loc, value);
1397 return builder.create<moore::CeilBIOp>(loc, value);
1401 return builder.create<moore::AsinBIOp>(loc, value);
1405 return builder.create<moore::AcosBIOp>(loc, value);
1409 return builder.create<moore::AtanBIOp>(loc, value);
1413 return builder.create<moore::SinhBIOp>(loc, value);
1417 return builder.create<moore::CoshBIOp>(loc, value);
1421 return builder.create<moore::TanhBIOp>(loc, value);
1425 return builder.create<moore::AsinhBIOp>(loc, value);
1429 return builder.create<moore::AcoshBIOp>(loc, value);
1433 return builder.create<moore::AtanhBIOp>(loc, value);
1435 .Default([&]() -> Value {
return {}; });
1436 return systemCallRes();
assert(baseType &&"element must be base type")
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.
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.