10#include "slang/ast/EvalContext.h"
11#include "slang/ast/SystemSubroutine.h"
12#include "slang/syntax/AllSyntax.h"
13#include "llvm/ADT/ScopeExit.h"
16using namespace ImportVerilog;
21 if (svint.hasUnknown()) {
22 unsigned numWords = svint.getNumWords() / 2;
23 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
24 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
25 return FVInt(APInt(svint.getBitWidth(), value),
26 APInt(svint.getBitWidth(), unknown));
28 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
29 return FVInt(APInt(svint.getBitWidth(), value));
36 const slang::ConstantRange &range) {
37 auto &builder =
context.builder;
38 auto indexType = cast<moore::UnpackedType>(index.getType());
41 auto lo = range.lower();
42 auto hi = range.upper();
43 auto offset = range.isLittleEndian() ? lo : hi;
46 const bool needSigned = (lo < 0) || (hi < 0);
49 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
54 unsigned want = needSigned
55 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
56 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
59 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
62 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
63 index =
context.materializeConversion(intType, index, needSigned, loc);
66 if (range.isLittleEndian())
69 return moore::NegOp::create(builder, loc, index);
73 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
74 if (range.isLittleEndian())
75 return moore::SubOp::create(builder, loc, index, offsetConst);
77 return moore::SubOp::create(builder, loc, offsetConst, index);
82 static_assert(int(slang::TimeUnit::Seconds) == 0);
83 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
84 static_assert(int(slang::TimeUnit::Microseconds) == 2);
85 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
86 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
87 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
89 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
90 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
91 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
93 auto exp =
static_cast<unsigned>(
context.timeScale.base.unit);
96 auto scale =
static_cast<uint64_t
>(
context.timeScale.base.magnitude);
103 const slang::ast::ClassPropertySymbol &expr) {
104 auto loc =
context.convertLocation(expr.location);
105 auto builder =
context.builder;
107 auto type =
context.convertType(expr.getType());
109 mlir::Value instRef =
context.getImplicitThisRef();
111 mlir::emitError(loc) <<
"class property '" << expr.name
112 <<
"' referenced without an implicit 'this'";
116 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
117 auto fieldTy = cast<moore::UnpackedType>(type);
118 auto fieldRefTy = moore::RefType::get(fieldTy);
120 moore::ClassHandleType classTy =
121 cast<moore::ClassHandleType>(instRef.getType());
123 auto targetClassHandle =
124 context.getAncestorClassWithProperty(classTy, expr.name, loc);
125 if (!targetClassHandle)
128 auto upcastRef =
context.materializeConversion(targetClassHandle, instRef,
129 false, instRef.getLoc());
133 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
134 upcastRef, fieldSym);
146 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
147 : context(context), loc(loc), builder(context.builder),
148 isLvalue(isLvalue) {}
154 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
161 Value visit(
const slang::ast::ElementSelectExpression &expr) {
163 auto value = convertLvalueOrRvalueExpression(expr.value());
168 auto derefType = value.getType();
170 derefType = cast<moore::RefType>(derefType).getNestedType();
171 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType>(
173 mlir::emitError(loc) <<
"unsupported expression: element select into "
174 << expr.value().type->toString() <<
"\n";
179 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
180 auto range = expr.value().type->getFixedRange();
181 if (
auto *constValue = expr.selector().getConstant();
182 constValue && constValue->isInteger()) {
183 assert(!constValue->hasUnknown());
184 assert(constValue->size() <= 32);
186 auto lowBit = constValue->integer().as<uint32_t>().value();
188 return moore::ExtractRefOp::create(builder, loc, resultType, value,
189 range.translateIndex(lowBit));
191 return moore::ExtractOp::create(builder, loc, resultType, value,
192 range.translateIndex(lowBit));
200 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
203 return moore::DynExtractOp::create(builder, loc, resultType, value,
208 Value visit(
const slang::ast::RangeSelectExpression &expr) {
210 auto value = convertLvalueOrRvalueExpression(expr.value());
214 std::optional<int32_t> constLeft;
215 std::optional<int32_t> constRight;
216 if (
auto *constant = expr.left().getConstant())
217 constLeft = constant->integer().as<int32_t>();
218 if (
auto *constant = expr.right().getConstant())
219 constRight = constant->integer().as<int32_t>();
225 <<
"unsupported expression: range select with non-constant bounds";
245 int32_t offsetConst = 0;
246 auto range = expr.value().type->getFixedRange();
248 using slang::ast::RangeSelectionKind;
249 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
254 assert(constRight &&
"constness checked in slang");
255 offsetConst = *constRight;
266 offsetConst = *constLeft;
277 int32_t offsetAdd = 0;
282 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
283 range.isLittleEndian()) {
284 assert(constRight &&
"constness checked in slang");
285 offsetAdd = 1 - *constRight;
291 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
292 !range.isLittleEndian()) {
293 assert(constRight &&
"constness checked in slang");
294 offsetAdd = *constRight - 1;
298 if (offsetAdd != 0) {
300 offsetDyn = moore::AddOp::create(
301 builder, loc, offsetDyn,
302 moore::ConstantOp::create(
303 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
307 offsetConst += offsetAdd;
318 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
323 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
326 return moore::DynExtractOp::create(builder, loc, resultType, value,
330 offsetConst = range.translateIndex(offsetConst);
332 return moore::ExtractRefOp::create(builder, loc, resultType, value,
335 return moore::ExtractOp::create(builder, loc, resultType, value,
342 Value visit(
const slang::ast::ConcatenationExpression &expr) {
343 SmallVector<Value> operands;
344 for (
auto *operand : expr.operands()) {
348 if (operand->type->isVoid())
350 auto value = convertLvalueOrRvalueExpression(*operand);
357 operands.push_back(value);
360 return moore::ConcatRefOp::create(builder, loc, operands);
362 return moore::ConcatOp::create(builder, loc, operands);
366 Value visit(
const slang::ast::MemberAccessExpression &expr) {
371 auto *valueType = expr.value().type.get();
372 auto memberName = builder.getStringAttr(expr.member.name);
375 if (valueType->isStruct()) {
377 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
379 auto value = convertLvalueOrRvalueExpression(expr.value());
384 return moore::StructExtractRefOp::create(builder, loc, resultType,
386 return moore::StructExtractOp::create(builder, loc, resultType,
391 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
393 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
395 auto value = convertLvalueOrRvalueExpression(expr.value());
400 return moore::UnionExtractRefOp::create(builder, loc, resultType,
402 return moore::UnionExtractOp::create(builder, loc, type, memberName,
407 if (valueType->isClass()) {
411 auto targetTy = cast<moore::ClassHandleType>(valTy);
416 auto upcastTargetTy =
430 mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.member.name);
431 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
434 Value fieldRef = moore::ClassPropertyRefOp::create(
435 builder, loc, fieldRefTy, baseVal, fieldSym);
438 return isLvalue ? fieldRef
439 : moore::ReadOp::create(builder, loc, fieldRef);
442 mlir::emitError(loc,
"expression of type ")
443 << valueType->toString() <<
" has no member fields";
455struct RvalueExprVisitor :
public ExprVisitor {
457 : ExprVisitor(
context, loc, false) {}
458 using ExprVisitor::visit;
461 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
462 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
463 auto lvalue =
context.lvalueStack.back();
464 return moore::ReadOp::create(builder, loc, lvalue);
468 Value visit(
const slang::ast::NamedValueExpression &expr) {
470 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
471 if (isa<moore::RefType>(value.getType())) {
472 auto readOp = moore::ReadOp::create(builder, loc, value);
473 if (
context.rvalueReadCallback)
474 context.rvalueReadCallback(readOp);
475 value = readOp.getResult();
481 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
482 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
483 return moore::ReadOp::create(builder, loc, value);
487 if (
auto *
const property =
488 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
490 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
494 auto constant =
context.evaluateConstant(expr);
495 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
500 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
501 d.attachNote(
context.convertLocation(expr.symbol.location))
502 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
507 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
508 auto hierLoc =
context.convertLocation(expr.symbol.location);
509 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
510 if (isa<moore::RefType>(value.getType())) {
511 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
512 if (
context.rvalueReadCallback)
513 context.rvalueReadCallback(readOp);
514 value = readOp.getResult();
521 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
522 << expr.symbol.name <<
"`";
523 d.attachNote(hierLoc) <<
"no rvalue generated for "
524 << slang::ast::toString(expr.symbol.kind);
529 Value visit(
const slang::ast::ConversionExpression &expr) {
530 auto type =
context.convertType(*expr.type);
533 return context.convertRvalueExpression(expr.operand(), type);
537 Value visit(
const slang::ast::AssignmentExpression &expr) {
538 auto lhs =
context.convertLvalueExpression(expr.left());
543 context.lvalueStack.push_back(lhs);
544 auto rhs =
context.convertRvalueExpression(
545 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
546 context.lvalueStack.pop_back();
553 if (!expr.isNonBlocking()) {
554 if (expr.timingControl)
555 if (failed(
context.convertTimingControl(*expr.timingControl)))
557 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
558 if (
context.variableAssignCallback)
559 context.variableAssignCallback(assignOp);
564 if (expr.timingControl) {
566 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
567 auto delay =
context.convertRvalueExpression(
568 ctrl->expr, moore::TimeType::get(builder.getContext()));
571 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
572 builder, loc, lhs, rhs, delay);
573 if (
context.variableAssignCallback)
574 context.variableAssignCallback(assignOp);
579 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
581 <<
"unsupported non-blocking assignment timing control: "
582 << slang::ast::toString(expr.timingControl->kind);
585 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
586 if (
context.variableAssignCallback)
587 context.variableAssignCallback(assignOp);
593 template <
class ConcreteOp>
594 Value createReduction(Value arg,
bool invert) {
595 arg =
context.convertToSimpleBitVector(arg);
598 Value result = ConcreteOp::create(builder, loc, arg);
600 result = moore::NotOp::create(builder, loc, result);
605 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
606 auto preValue = moore::ReadOp::create(builder, loc, arg);
612 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
615 auto one = moore::ConstantOp::create(
616 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
618 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
619 : moore::SubOp::create(builder, loc, preValue, one).getResult();
621 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
622 if (
context.variableAssignCallback)
623 context.variableAssignCallback(assignOp);
632 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
633 Value preValue = moore::ReadOp::create(builder, loc, arg);
636 bool isTime = isa<moore::TimeType>(preValue.getType());
638 preValue =
context.materializeConversion(
639 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
640 preValue,
false, loc);
642 moore::RealType realTy =
643 llvm::dyn_cast<moore::RealType>(preValue.getType());
648 if (realTy.getWidth() == moore::RealWidth::f32) {
649 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
650 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
652 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
654 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
657 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
661 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
662 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
665 postValue =
context.materializeConversion(
666 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
669 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
671 if (
context.variableAssignCallback)
672 context.variableAssignCallback(assignOp);
679 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
680 Type opFTy =
context.convertType(*expr.operand().type);
682 using slang::ast::UnaryOperator;
684 if (expr.op == UnaryOperator::Preincrement ||
685 expr.op == UnaryOperator::Predecrement ||
686 expr.op == UnaryOperator::Postincrement ||
687 expr.op == UnaryOperator::Postdecrement)
688 arg =
context.convertLvalueExpression(expr.operand());
690 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
695 if (isa<moore::TimeType>(arg.getType()))
696 arg =
context.materializeConversion(
697 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
702 case UnaryOperator::Plus:
704 case UnaryOperator::Minus:
705 return moore::NegRealOp::create(builder, loc, arg);
707 case UnaryOperator::Preincrement:
708 return createRealIncrement(arg,
true,
false);
709 case UnaryOperator::Predecrement:
710 return createRealIncrement(arg,
false,
false);
711 case UnaryOperator::Postincrement:
712 return createRealIncrement(arg,
true,
true);
713 case UnaryOperator::Postdecrement:
714 return createRealIncrement(arg,
false,
true);
716 case UnaryOperator::LogicalNot:
717 arg =
context.convertToBool(arg);
720 return moore::NotOp::create(builder, loc, arg);
723 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
724 <<
" not supported with real values!\n";
730 Value visit(
const slang::ast::UnaryExpression &expr) {
732 const auto *floatType =
733 expr.operand().type->as_if<slang::ast::FloatingType>();
736 return visitRealUOp(expr);
738 using slang::ast::UnaryOperator;
740 if (expr.op == UnaryOperator::Preincrement ||
741 expr.op == UnaryOperator::Predecrement ||
742 expr.op == UnaryOperator::Postincrement ||
743 expr.op == UnaryOperator::Postdecrement)
744 arg =
context.convertLvalueExpression(expr.operand());
746 arg =
context.convertRvalueExpression(expr.operand());
753 case UnaryOperator::Plus:
754 return context.convertToSimpleBitVector(arg);
756 case UnaryOperator::Minus:
757 arg =
context.convertToSimpleBitVector(arg);
760 return moore::NegOp::create(builder, loc, arg);
762 case UnaryOperator::BitwiseNot:
763 arg =
context.convertToSimpleBitVector(arg);
766 return moore::NotOp::create(builder, loc, arg);
768 case UnaryOperator::BitwiseAnd:
769 return createReduction<moore::ReduceAndOp>(arg,
false);
770 case UnaryOperator::BitwiseOr:
771 return createReduction<moore::ReduceOrOp>(arg,
false);
772 case UnaryOperator::BitwiseXor:
773 return createReduction<moore::ReduceXorOp>(arg,
false);
774 case UnaryOperator::BitwiseNand:
775 return createReduction<moore::ReduceAndOp>(arg,
true);
776 case UnaryOperator::BitwiseNor:
777 return createReduction<moore::ReduceOrOp>(arg,
true);
778 case UnaryOperator::BitwiseXnor:
779 return createReduction<moore::ReduceXorOp>(arg,
true);
781 case UnaryOperator::LogicalNot:
782 arg =
context.convertToBool(arg);
785 return moore::NotOp::create(builder, loc, arg);
787 case UnaryOperator::Preincrement:
788 return createIncrement(arg,
true,
false);
789 case UnaryOperator::Predecrement:
790 return createIncrement(arg,
false,
false);
791 case UnaryOperator::Postincrement:
792 return createIncrement(arg,
true,
true);
793 case UnaryOperator::Postdecrement:
794 return createIncrement(arg,
false,
true);
797 mlir::emitError(loc,
"unsupported unary operator");
802 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
803 std::optional<Domain> domain = std::nullopt) {
804 using slang::ast::BinaryOperator;
808 lhs =
context.convertToBool(lhs, domain.value());
809 rhs =
context.convertToBool(rhs, domain.value());
811 lhs =
context.convertToBool(lhs);
812 rhs =
context.convertToBool(rhs);
819 case BinaryOperator::LogicalAnd:
820 return moore::AndOp::create(builder, loc, lhs, rhs);
822 case BinaryOperator::LogicalOr:
823 return moore::OrOp::create(builder, loc, lhs, rhs);
825 case BinaryOperator::LogicalImplication: {
827 auto notLHS = moore::NotOp::create(builder, loc, lhs);
828 return moore::OrOp::create(builder, loc, notLHS, rhs);
831 case BinaryOperator::LogicalEquivalence: {
833 auto notLHS = moore::NotOp::create(builder, loc, lhs);
834 auto notRHS = moore::NotOp::create(builder, loc, rhs);
835 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
836 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
837 return moore::OrOp::create(builder, loc, both, notBoth);
841 llvm_unreachable(
"not a logical BinaryOperator");
845 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
847 auto lhs =
context.convertRvalueExpression(expr.left());
850 auto rhs =
context.convertRvalueExpression(expr.right());
854 if (isa<moore::TimeType>(lhs.getType()) ||
855 isa<moore::TimeType>(rhs.getType())) {
856 lhs =
context.materializeConversion(
857 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
859 rhs =
context.materializeConversion(
860 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
864 using slang::ast::BinaryOperator;
866 case BinaryOperator::Add:
867 return moore::AddRealOp::create(builder, loc, lhs, rhs);
868 case BinaryOperator::Subtract:
869 return moore::SubRealOp::create(builder, loc, lhs, rhs);
870 case BinaryOperator::Multiply:
871 return moore::MulRealOp::create(builder, loc, lhs, rhs);
872 case BinaryOperator::Divide:
873 return moore::DivRealOp::create(builder, loc, lhs, rhs);
874 case BinaryOperator::Power:
875 return moore::PowRealOp::create(builder, loc, lhs, rhs);
877 case BinaryOperator::Equality:
878 return moore::EqRealOp::create(builder, loc, lhs, rhs);
879 case BinaryOperator::Inequality:
880 return moore::NeRealOp::create(builder, loc, lhs, rhs);
882 case BinaryOperator::GreaterThan:
883 return moore::FgtOp::create(builder, loc, lhs, rhs);
884 case BinaryOperator::LessThan:
885 return moore::FltOp::create(builder, loc, lhs, rhs);
886 case BinaryOperator::GreaterThanEqual:
887 return moore::FgeOp::create(builder, loc, lhs, rhs);
888 case BinaryOperator::LessThanEqual:
889 return moore::FleOp::create(builder, loc, lhs, rhs);
891 case BinaryOperator::LogicalAnd:
892 case BinaryOperator::LogicalOr:
893 case BinaryOperator::LogicalImplication:
894 case BinaryOperator::LogicalEquivalence:
895 return buildLogicalBOp(expr.op, lhs, rhs);
898 mlir::emitError(loc) <<
"Binary operator "
899 << slang::ast::toString(expr.op)
900 <<
" not supported with real valued operands!\n";
907 template <
class ConcreteOp>
908 Value createBinary(Value lhs, Value rhs) {
909 lhs =
context.convertToSimpleBitVector(lhs);
912 rhs =
context.convertToSimpleBitVector(rhs);
915 return ConcreteOp::create(builder, loc, lhs, rhs);
919 Value visit(
const slang::ast::BinaryExpression &expr) {
921 const auto *rhsFloatType =
922 expr.right().type->as_if<slang::ast::FloatingType>();
923 const auto *lhsFloatType =
924 expr.left().type->as_if<slang::ast::FloatingType>();
927 if (rhsFloatType || lhsFloatType)
928 return visitRealBOp(expr);
930 auto lhs =
context.convertRvalueExpression(expr.left());
933 auto rhs =
context.convertRvalueExpression(expr.right());
938 Domain domain = Domain::TwoValued;
939 if (expr.type->isFourState() || expr.left().type->isFourState() ||
940 expr.right().type->isFourState())
941 domain = Domain::FourValued;
943 using slang::ast::BinaryOperator;
945 case BinaryOperator::Add:
946 return createBinary<moore::AddOp>(lhs, rhs);
947 case BinaryOperator::Subtract:
948 return createBinary<moore::SubOp>(lhs, rhs);
949 case BinaryOperator::Multiply:
950 return createBinary<moore::MulOp>(lhs, rhs);
951 case BinaryOperator::Divide:
952 if (expr.type->isSigned())
953 return createBinary<moore::DivSOp>(lhs, rhs);
955 return createBinary<moore::DivUOp>(lhs, rhs);
956 case BinaryOperator::Mod:
957 if (expr.type->isSigned())
958 return createBinary<moore::ModSOp>(lhs, rhs);
960 return createBinary<moore::ModUOp>(lhs, rhs);
961 case BinaryOperator::Power: {
966 auto rhsCast =
context.materializeConversion(
967 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
968 if (expr.type->isSigned())
969 return createBinary<moore::PowSOp>(lhs, rhsCast);
971 return createBinary<moore::PowUOp>(lhs, rhsCast);
974 case BinaryOperator::BinaryAnd:
975 return createBinary<moore::AndOp>(lhs, rhs);
976 case BinaryOperator::BinaryOr:
977 return createBinary<moore::OrOp>(lhs, rhs);
978 case BinaryOperator::BinaryXor:
979 return createBinary<moore::XorOp>(lhs, rhs);
980 case BinaryOperator::BinaryXnor: {
981 auto result = createBinary<moore::XorOp>(lhs, rhs);
984 return moore::NotOp::create(builder, loc, result);
987 case BinaryOperator::Equality:
988 if (isa<moore::UnpackedArrayType>(lhs.getType()))
989 return moore::UArrayCmpOp::create(
990 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
991 else if (isa<moore::StringType>(lhs.getType()))
992 return moore::StringCmpOp::create(
993 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
995 return createBinary<moore::EqOp>(lhs, rhs);
996 case BinaryOperator::Inequality:
997 if (isa<moore::UnpackedArrayType>(lhs.getType()))
998 return moore::UArrayCmpOp::create(
999 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1000 else if (isa<moore::StringType>(lhs.getType()))
1001 return moore::StringCmpOp::create(
1002 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1004 return createBinary<moore::NeOp>(lhs, rhs);
1005 case BinaryOperator::CaseEquality:
1006 return createBinary<moore::CaseEqOp>(lhs, rhs);
1007 case BinaryOperator::CaseInequality:
1008 return createBinary<moore::CaseNeOp>(lhs, rhs);
1009 case BinaryOperator::WildcardEquality:
1010 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1011 case BinaryOperator::WildcardInequality:
1012 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1014 case BinaryOperator::GreaterThanEqual:
1015 if (expr.left().type->isSigned())
1016 return createBinary<moore::SgeOp>(lhs, rhs);
1017 else if (isa<moore::StringType>(lhs.getType()))
1018 return moore::StringCmpOp::create(
1019 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1021 return createBinary<moore::UgeOp>(lhs, rhs);
1022 case BinaryOperator::GreaterThan:
1023 if (expr.left().type->isSigned())
1024 return createBinary<moore::SgtOp>(lhs, rhs);
1025 else if (isa<moore::StringType>(lhs.getType()))
1026 return moore::StringCmpOp::create(
1027 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1029 return createBinary<moore::UgtOp>(lhs, rhs);
1030 case BinaryOperator::LessThanEqual:
1031 if (expr.left().type->isSigned())
1032 return createBinary<moore::SleOp>(lhs, rhs);
1033 else if (isa<moore::StringType>(lhs.getType()))
1034 return moore::StringCmpOp::create(
1035 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1037 return createBinary<moore::UleOp>(lhs, rhs);
1038 case BinaryOperator::LessThan:
1039 if (expr.left().type->isSigned())
1040 return createBinary<moore::SltOp>(lhs, rhs);
1041 else if (isa<moore::StringType>(lhs.getType()))
1042 return moore::StringCmpOp::create(
1043 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1045 return createBinary<moore::UltOp>(lhs, rhs);
1047 case BinaryOperator::LogicalAnd:
1048 case BinaryOperator::LogicalOr:
1049 case BinaryOperator::LogicalImplication:
1050 case BinaryOperator::LogicalEquivalence:
1051 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1053 case BinaryOperator::LogicalShiftLeft:
1054 return createBinary<moore::ShlOp>(lhs, rhs);
1055 case BinaryOperator::LogicalShiftRight:
1056 return createBinary<moore::ShrOp>(lhs, rhs);
1057 case BinaryOperator::ArithmeticShiftLeft:
1058 return createBinary<moore::ShlOp>(lhs, rhs);
1059 case BinaryOperator::ArithmeticShiftRight: {
1062 lhs =
context.convertToSimpleBitVector(lhs);
1063 rhs =
context.convertToSimpleBitVector(rhs);
1066 if (expr.type->isSigned())
1067 return moore::AShrOp::create(builder, loc, lhs, rhs);
1068 return moore::ShrOp::create(builder, loc, lhs, rhs);
1072 mlir::emitError(loc,
"unsupported binary operator");
1077 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1078 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1082 Value visit(
const slang::ast::IntegerLiteral &expr) {
1083 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1087 Value visit(
const slang::ast::TimeLiteral &expr) {
1092 double value = std::round(expr.getValue() * scale);
1102 static constexpr uint64_t limit =
1103 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1104 if (value > limit) {
1105 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1109 return moore::ConstantTimeOp::create(builder, loc,
1110 static_cast<uint64_t
>(value));
1114 Value visit(
const slang::ast::ReplicationExpression &expr) {
1115 auto type =
context.convertType(*expr.type);
1116 auto value =
context.convertRvalueExpression(expr.concat());
1119 return moore::ReplicateOp::create(builder, loc, type, value);
1123 Value visit(
const slang::ast::InsideExpression &expr) {
1124 auto lhs =
context.convertToSimpleBitVector(
1125 context.convertRvalueExpression(expr.left()));
1129 SmallVector<Value> conditions;
1132 for (
const auto *listExpr : expr.rangeList()) {
1136 if (
const auto *openRange =
1137 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
1139 auto lowBound =
context.convertToSimpleBitVector(
1140 context.convertRvalueExpression(openRange->left()));
1141 auto highBound =
context.convertToSimpleBitVector(
1142 context.convertRvalueExpression(openRange->right()));
1143 if (!lowBound || !highBound)
1145 Value leftValue, rightValue;
1148 if (openRange->left().type->isSigned() ||
1149 expr.left().type->isSigned()) {
1150 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
1152 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
1154 if (openRange->right().type->isSigned() ||
1155 expr.left().type->isSigned()) {
1156 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
1158 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
1160 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
1163 if (!listExpr->type->isIntegral()) {
1164 if (listExpr->type->isUnpackedArray()) {
1166 loc,
"unpacked arrays in 'inside' expressions not supported");
1170 loc,
"only simple bit vectors supported in 'inside' expressions");
1174 auto value =
context.convertToSimpleBitVector(
1175 context.convertRvalueExpression(*listExpr));
1178 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
1180 conditions.push_back(cond);
1184 auto result = conditions.back();
1185 conditions.pop_back();
1186 while (!conditions.empty()) {
1187 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1188 conditions.pop_back();
1194 Value visit(
const slang::ast::ConditionalExpression &expr) {
1195 auto type =
context.convertType(*expr.type);
1198 if (expr.conditions.size() > 1) {
1199 mlir::emitError(loc)
1200 <<
"unsupported conditional expression with more than one condition";
1203 const auto &cond = expr.conditions[0];
1205 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1209 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1212 auto conditionalOp =
1213 moore::ConditionalOp::create(builder, loc, type, value);
1216 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1217 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1219 OpBuilder::InsertionGuard g(builder);
1222 builder.setInsertionPointToStart(&trueBlock);
1223 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1226 moore::YieldOp::create(builder, loc, trueValue);
1229 builder.setInsertionPointToStart(&falseBlock);
1230 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1233 moore::YieldOp::create(builder, loc, falseValue);
1235 return conditionalOp.getResult();
1239 Value visit(
const slang::ast::CallExpression &expr) {
1241 auto constant =
context.evaluateConstant(expr);
1242 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1246 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1252 std::pair<Value, moore::ClassHandleType>
1253 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1255 moore::ClassHandleType handleTy;
1259 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1260 thisRef =
context.convertRvalueExpression(*recvExpr);
1265 thisRef =
context.getImplicitThisRef();
1267 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1268 <<
"' called without an object";
1272 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1273 return {thisRef, handleTy};
1277 mlir::CallOpInterface
1278 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1280 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1281 SmallVector<Value> &arguments,
1282 SmallVector<Type> &resultTypes) {
1285 auto funcTy = lowering->
op.getFunctionType();
1286 auto expected0 = funcTy.getInput(0);
1287 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1290 auto implicitThisRef =
context.materializeConversion(
1291 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1294 SmallVector<Value> explicitArguments;
1295 explicitArguments.reserve(arguments.size() + 1);
1296 explicitArguments.push_back(implicitThisRef);
1297 explicitArguments.append(arguments.begin(), arguments.end());
1300 const bool isVirtual =
1301 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1304 auto calleeSym = lowering->
op.getSymName();
1306 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1310 auto funcName = subroutine->name;
1311 auto method = moore::VTableLoadMethodOp::create(
1312 builder, loc, funcTy, actualThisRef,
1313 SymbolRefAttr::get(
context.getContext(), funcName));
1314 return mlir::func::CallIndirectOp::create(builder, loc, method,
1319 Value visitCall(
const slang::ast::CallExpression &expr,
1320 const slang::ast::SubroutineSymbol *subroutine) {
1322 const bool isMethod = (subroutine->thisVar !=
nullptr);
1324 auto *lowering =
context.declareFunction(*subroutine);
1327 auto convertedFunction =
context.convertFunction(*subroutine);
1328 if (failed(convertedFunction))
1334 SmallVector<Value> arguments;
1335 for (
auto [callArg, declArg] :
1336 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1340 auto *expr = callArg;
1341 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1342 expr = &assign->left();
1345 auto type =
context.convertType(declArg->getType());
1346 if (declArg->direction == slang::ast::ArgumentDirection::In) {
1347 value =
context.convertRvalueExpression(*expr, type);
1349 Value lvalue =
context.convertLvalueExpression(*expr);
1350 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
1354 context.materializeConversion(moore::RefType::get(unpackedType),
1355 lvalue, expr->type->isSigned(), loc);
1359 arguments.push_back(value);
1363 auto materializeCaptureAtCall = [&](Value cap) -> Value {
1365 auto refTy = dyn_cast<moore::RefType>(cap.getType());
1367 lowering->
op.emitError(
1368 "expected captured value to be moore::RefType");
1375 Region *capRegion = [&]() -> Region * {
1376 if (
auto ba = dyn_cast<BlockArgument>(cap))
1377 return ba.getOwner()->getParent();
1378 if (
auto *def = cap.getDefiningOp())
1379 return def->getParentRegion();
1383 Region *callRegion =
1384 builder.getBlock() ? builder.getBlock()->getParent() :
nullptr;
1386 for (Region *r = callRegion; r; r = r->getParentRegion()) {
1387 if (r == capRegion) {
1394 lowering->
op.emitError()
1395 <<
"cannot materialize captured ref at call site; non-symbol "
1397 << (cap.getDefiningOp()
1398 ? cap.getDefiningOp()->getName().getStringRef()
1403 for (Value cap : lowering->captures) {
1404 Value mat = materializeCaptureAtCall(cap);
1407 arguments.push_back(mat);
1412 SmallVector<Type> resultTypes(
1413 lowering->
op.getFunctionType().getResults().begin(),
1414 lowering->
op.getFunctionType().getResults().end());
1416 mlir::CallOpInterface callOp;
1420 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1421 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1422 arguments, resultTypes);
1426 mlir::func::CallOp::create(builder, loc, lowering->
op, arguments);
1429 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1433 if (resultTypes.size() == 0)
1434 return mlir::UnrealizedConversionCastOp::create(
1435 builder, loc, moore::VoidType::get(
context.getContext()),
1443 Value visitCall(
const slang::ast::CallExpression &expr,
1444 const slang::ast::CallExpression::SystemCallInfo &info) {
1445 const auto &subroutine = *
info.subroutine;
1450 bool isAssertionCall =
1451 llvm::StringSwitch<bool>(subroutine.name)
1452 .Cases({
"$rose",
"$fell",
"$stable",
"$past"},
true)
1455 if (isAssertionCall)
1456 return context.convertAssertionCallExpression(expr, info, loc);
1458 auto args = expr.arguments();
1460 FailureOr<Value> result;
1470 if (!subroutine.name.compare(
"$sformatf")) {
1472 auto fmtValue =
context.convertFormatString(
1473 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1474 if (failed(fmtValue))
1476 return fmtValue.value();
1485 switch (args.size()) {
1487 result =
context.convertSystemCallArity0(subroutine, loc);
1491 value =
context.convertRvalueExpression(*args[0]);
1494 result =
context.convertSystemCallArity1(subroutine, loc, value);
1498 value =
context.convertRvalueExpression(*args[0]);
1499 value2 =
context.convertRvalueExpression(*args[1]);
1500 if (!value || !value2)
1502 result =
context.convertSystemCallArity2(subroutine, loc, value, value2);
1518 auto ty =
context.convertType(*expr.type);
1519 return context.materializeConversion(ty, *result, expr.type->isSigned(),
1524 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
1530 Value visit(
const slang::ast::StringLiteral &expr) {
1531 auto type =
context.convertType(*expr.type);
1532 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1536 Value visit(
const slang::ast::RealLiteral &expr) {
1537 auto fTy = mlir::Float64Type::get(
context.getContext());
1538 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
1539 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
1544 FailureOr<SmallVector<Value>>
1545 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1546 std::variant<Type, ArrayRef<Type>> expectedTypes,
1547 unsigned replCount) {
1548 const auto &elts = expr.elements();
1549 const size_t elementCount = elts.size();
1552 const bool hasBroadcast =
1553 std::holds_alternative<Type>(expectedTypes) &&
1554 static_cast<bool>(std::get<Type>(expectedTypes));
1556 const bool hasPerElem =
1557 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1558 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1562 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1563 if (types.size() != elementCount) {
1564 mlir::emitError(loc)
1565 <<
"assignment pattern arity mismatch: expected " << types.size()
1566 <<
" elements, got " << elementCount;
1571 SmallVector<Value> converted;
1572 converted.reserve(elementCount * std::max(1u, replCount));
1575 if (!hasBroadcast && !hasPerElem) {
1577 for (
const auto *elementExpr : elts) {
1578 Value v =
context.convertRvalueExpression(*elementExpr);
1581 converted.push_back(v);
1583 }
else if (hasBroadcast) {
1585 Type want = std::get<Type>(expectedTypes);
1586 for (
const auto *elementExpr : elts) {
1587 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1588 :
context.convertRvalueExpression(*elementExpr);
1591 converted.push_back(v);
1594 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1595 for (
size_t i = 0; i < elementCount; ++i) {
1596 Type want = types[i];
1597 const auto *elementExpr = elts[i];
1598 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1599 :
context.convertRvalueExpression(*elementExpr);
1602 converted.push_back(v);
1606 for (
unsigned i = 1; i < replCount; ++i)
1607 converted.append(converted.begin(), converted.begin() + elementCount);
1613 Value visitAssignmentPattern(
1614 const slang::ast::AssignmentPatternExpressionBase &expr,
1615 unsigned replCount = 1) {
1616 auto type =
context.convertType(*expr.type);
1617 const auto &elts = expr.elements();
1620 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1621 auto elements = convertElements(expr, {}, replCount);
1623 if (failed(elements))
1626 assert(intType.getWidth() == elements->size());
1627 std::reverse(elements->begin(), elements->end());
1628 return moore::ConcatOp::create(builder, loc, intType, *elements);
1632 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1633 SmallVector<Type> expectedTy;
1634 expectedTy.reserve(structType.getMembers().size());
1635 for (
auto member : structType.getMembers())
1636 expectedTy.push_back(member.type);
1638 FailureOr<SmallVector<Value>> elements;
1639 if (expectedTy.size() == elts.size())
1640 elements = convertElements(expr, expectedTy, replCount);
1642 elements = convertElements(expr, {}, replCount);
1644 if (failed(elements))
1647 assert(structType.getMembers().size() == elements->size());
1648 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1652 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1653 SmallVector<Type> expectedTy;
1654 expectedTy.reserve(structType.getMembers().size());
1655 for (
auto member : structType.getMembers())
1656 expectedTy.push_back(member.type);
1658 FailureOr<SmallVector<Value>> elements;
1659 if (expectedTy.size() == elts.size())
1660 elements = convertElements(expr, expectedTy, replCount);
1662 elements = convertElements(expr, {}, replCount);
1664 if (failed(elements))
1667 assert(structType.getMembers().size() == elements->size());
1669 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1673 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
1675 convertElements(expr, arrayType.getElementType(), replCount);
1677 if (failed(elements))
1680 assert(arrayType.getSize() == elements->size());
1681 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1685 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
1687 convertElements(expr, arrayType.getElementType(), replCount);
1689 if (failed(elements))
1692 assert(arrayType.getSize() == elements->size());
1693 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1696 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
1700 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
1701 return visitAssignmentPattern(expr);
1704 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
1705 return visitAssignmentPattern(expr);
1708 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
1710 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
1711 assert(count &&
"Slang guarantees constant non-zero replication count");
1712 return visitAssignmentPattern(expr, *count);
1715 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1716 SmallVector<Value> operands;
1717 for (
auto stream : expr.streams()) {
1718 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
1719 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1720 mlir::emitError(operandLoc)
1721 <<
"Moore only support streaming "
1722 "concatenation with fixed size 'with expression'";
1726 if (stream.constantWithWidth.has_value()) {
1727 value =
context.convertRvalueExpression(*stream.withExpr);
1728 auto type = cast<moore::UnpackedType>(value.getType());
1729 auto intType = moore::IntType::get(
1730 context.getContext(), type.getBitSize().value(), type.getDomain());
1732 value =
context.materializeConversion(intType, value,
false, loc);
1734 value =
context.convertRvalueExpression(*stream.operand);
1737 value =
context.convertToSimpleBitVector(value);
1740 operands.push_back(value);
1744 if (operands.size() == 1) {
1747 value = operands.front();
1749 value = moore::ConcatOp::create(builder, loc, operands).getResult();
1752 if (expr.getSliceSize() == 0) {
1756 auto type = cast<moore::IntType>(value.getType());
1757 SmallVector<Value> slicedOperands;
1758 auto iterMax = type.getWidth() / expr.getSliceSize();
1759 auto remainSize = type.getWidth() % expr.getSliceSize();
1761 for (
size_t i = 0; i < iterMax; i++) {
1762 auto extractResultType = moore::IntType::get(
1763 context.getContext(), expr.getSliceSize(), type.getDomain());
1765 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
1766 value, i * expr.getSliceSize());
1767 slicedOperands.push_back(extracted);
1771 auto extractResultType = moore::IntType::get(
1772 context.getContext(), remainSize, type.getDomain());
1775 moore::ExtractOp::create(builder, loc, extractResultType, value,
1776 iterMax * expr.getSliceSize());
1777 slicedOperands.push_back(extracted);
1780 return moore::ConcatOp::create(builder, loc, slicedOperands);
1783 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1784 return context.convertAssertionExpression(expr.body, loc);
1799 Value visit(
const slang::ast::NewClassExpression &expr) {
1800 auto type =
context.convertType(*expr.type);
1801 auto classTy = dyn_cast<moore::ClassHandleType>(type);
1807 if (!classTy && expr.isSuperClass) {
1808 newObj =
context.getImplicitThisRef();
1809 if (!newObj || !newObj.getType() ||
1810 !isa<moore::ClassHandleType>(newObj.getType())) {
1811 mlir::emitError(loc) <<
"implicit this ref was not set while "
1812 "converting new class function";
1815 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
1817 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
1818 context.intoModuleOp, thisType.getClassSym()));
1819 auto baseClassSym = classDecl.getBase();
1820 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
1821 baseClassSym.value());
1824 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
1827 const auto *constructor = expr.constructorCall();
1832 if (
const auto *callConstructor =
1833 constructor->as_if<slang::ast::CallExpression>())
1834 if (
const auto *subroutine =
1835 std::get_if<const slang::ast::SubroutineSymbol *>(
1836 &callConstructor->subroutine)) {
1839 if (!(*subroutine)->thisVar) {
1840 mlir::emitError(loc) <<
"Expected subroutine called by new to use an "
1841 "implicit this reference";
1844 if (failed(
context.convertFunction(**subroutine)))
1847 auto savedThis =
context.currentThisRef;
1848 context.currentThisRef = newObj;
1850 llvm::make_scope_exit([&] {
context.currentThisRef = savedThis; });
1852 if (!visitCall(*callConstructor, *subroutine))
1861 template <
typename T>
1862 Value visit(T &&node) {
1863 mlir::emitError(loc,
"unsupported expression: ")
1864 << slang::ast::toString(node.kind);
1868 Value visitInvalid(
const slang::ast::Expression &expr) {
1869 mlir::emitError(loc,
"invalid expression");
1880struct LvalueExprVisitor :
public ExprVisitor {
1882 : ExprVisitor(
context, loc, true) {}
1883 using ExprVisitor::visit;
1886 Value visit(
const slang::ast::NamedValueExpression &expr) {
1888 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
1892 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
1893 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
1895 if (
auto *
const property =
1896 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
1900 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
1901 d.attachNote(
context.convertLocation(expr.symbol.location))
1902 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1907 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
1909 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
1913 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
1914 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
1918 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
1919 << expr.symbol.name <<
"`";
1920 d.attachNote(
context.convertLocation(expr.symbol.location))
1921 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
1925 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1926 SmallVector<Value> operands;
1927 for (
auto stream : expr.streams()) {
1928 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
1929 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1930 mlir::emitError(operandLoc)
1931 <<
"Moore only support streaming "
1932 "concatenation with fixed size 'with expression'";
1936 if (stream.constantWithWidth.has_value()) {
1937 value =
context.convertLvalueExpression(*stream.withExpr);
1938 auto type = cast<moore::UnpackedType>(
1939 cast<moore::RefType>(value.getType()).getNestedType());
1940 auto intType = moore::RefType::get(moore::IntType::get(
1941 context.getContext(), type.getBitSize().value(), type.getDomain()));
1943 value =
context.materializeConversion(intType, value,
false, loc);
1945 value =
context.convertLvalueExpression(*stream.operand);
1950 operands.push_back(value);
1953 if (operands.size() == 1) {
1956 value = operands.front();
1958 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
1961 if (expr.getSliceSize() == 0) {
1965 auto type = cast<moore::IntType>(
1966 cast<moore::RefType>(value.getType()).getNestedType());
1967 SmallVector<Value> slicedOperands;
1968 auto widthSum = type.getWidth();
1969 auto domain = type.getDomain();
1970 auto iterMax = widthSum / expr.getSliceSize();
1971 auto remainSize = widthSum % expr.getSliceSize();
1973 for (
size_t i = 0; i < iterMax; i++) {
1974 auto extractResultType = moore::RefType::get(moore::IntType::get(
1975 context.getContext(), expr.getSliceSize(), domain));
1977 auto extracted = moore::ExtractRefOp::create(
1978 builder, loc, extractResultType, value, i * expr.getSliceSize());
1979 slicedOperands.push_back(extracted);
1983 auto extractResultType = moore::RefType::get(
1984 moore::IntType::get(
context.getContext(), remainSize, domain));
1987 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
1988 iterMax * expr.getSliceSize());
1989 slicedOperands.push_back(extracted);
1992 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
1996 template <
typename T>
1997 Value visit(T &&node) {
1998 return context.convertRvalueExpression(node);
2001 Value visitInvalid(
const slang::ast::Expression &expr) {
2002 mlir::emitError(loc,
"invalid expression");
2012Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
2013 Type requiredType) {
2015 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2016 if (value && requiredType)
2024 return expr.visit(LvalueExprVisitor(*
this, loc));
2032 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2033 if (type.getBitSize() == 1)
2035 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2036 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2037 mlir::emitError(value.getLoc(),
"expression of type ")
2038 << value.getType() <<
" cannot be cast to a boolean";
2044 const slang::ast::Type &astType,
2046 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2050 if (svreal.isShortReal() &&
2051 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2052 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2053 }
else if (svreal.isReal() &&
2054 floatType->floatKind == slang::ast::FloatingType::Real) {
2055 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2057 mlir::emitError(loc) <<
"invalid real constant";
2061 return moore::ConstantRealOp::create(
builder, loc, attr);
2066 const slang::ast::Type &astType,
2068 slang::ConstantValue intVal = stringLiteral.convertToInt();
2069 auto effectiveWidth = intVal.getEffectiveWidth();
2070 if (!effectiveWidth)
2073 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2075 if (astType.isString()) {
2076 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2077 stringLiteral.toString())
2079 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2086 const slang::ast::Type &astType, Location loc) {
2091 bool typeIsFourValued =
false;
2092 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2096 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2097 fvint.hasUnknown() || typeIsFourValued
2100 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2105 const slang::ConstantValue &constant,
2106 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2114 if (astType.elementType.isIntegral())
2115 bitWidth = astType.elementType.getBitWidth();
2119 bool typeIsFourValued =
false;
2122 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2133 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2135 auto arrType = moore::UnpackedArrayType::get(
2136 getContext(), constant.elements().size(), intType);
2138 llvm::SmallVector<mlir::Value> elemVals;
2139 moore::ConstantOp constOp;
2141 mlir::OpBuilder::InsertionGuard guard(
builder);
2144 for (
auto elem : constant.elements()) {
2146 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2147 elemVals.push_back(constOp.getResult());
2152 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2154 return arrayOp.getResult();
2158 const slang::ast::Type &type, Location loc) {
2160 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2162 if (constant.isInteger())
2164 if (constant.isReal() || constant.isShortReal())
2166 if (constant.isString())
2174 using slang::ast::EvalFlags;
2175 slang::ast::EvalContext evalContext(
2177 slang::ast::LookupLocation::max),
2178 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2179 return expr.eval(evalContext);
2188 auto type = moore::IntType::get(
getContext(), 1, domain);
2195 if (isa<moore::IntType>(value.getType()))
2202 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2203 if (
auto sbvType = packed.getSimpleBitVector())
2206 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2207 <<
" cannot be cast to a simple bit vector";
2216 if (isa<moore::IntType>(value.getType()))
2219 auto &builder =
context.builder;
2220 auto packedType = cast<moore::PackedType>(value.getType());
2221 auto intType = packedType.getSimpleBitVector();
2226 if (isa<moore::TimeType>(packedType) &&
2228 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2229 auto scale = moore::ConstantOp::create(builder, loc, intType,
2231 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2237 if (packedType.containsTimeType()) {
2238 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2239 <<
" cannot be converted to " << intType
2240 <<
"; contains a time type";
2245 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2253 Value value, Location loc) {
2254 if (value.getType() == packedType)
2257 auto &builder =
context.builder;
2258 auto intType = cast<moore::IntType>(value.getType());
2263 if (isa<moore::TimeType>(packedType) &&
2265 auto scale = moore::ConstantOp::create(builder, loc, intType,
2267 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2268 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2275 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2276 <<
" cannot be converted to " << packedType
2277 <<
"; contains a time type";
2282 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2288 moore::ClassHandleType expectedHandleTy) {
2289 auto loc = actualHandle.getLoc();
2291 auto actualTy = actualHandle.getType();
2292 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2293 if (!actualHandleTy) {
2294 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2300 if (actualHandleTy == expectedHandleTy)
2301 return actualHandle;
2303 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
2304 mlir::emitError(loc)
2305 <<
"receiver class " << actualHandleTy.getClassSym()
2306 <<
" is not the same as, or derived from, expected base class "
2307 << expectedHandleTy.getClassSym().getRootReference();
2312 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
2313 expectedHandleTy, actualHandle)
2321 if (type == value.getType())
2326 auto dstPacked = dyn_cast<moore::PackedType>(type);
2327 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2328 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2329 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2331 if (dstInt && srcInt) {
2339 auto resizedType = moore::IntType::get(
2340 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2341 if (dstInt.getWidth() < srcInt.getWidth()) {
2342 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2343 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2345 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2347 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2351 if (dstInt.getDomain() != srcInt.getDomain()) {
2353 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2355 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2363 assert(value.getType() == type);
2368 if (isa<moore::StringType>(type) &&
2369 isa<moore::FormatStringType>(value.getType())) {
2370 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2374 if (isa<moore::FormatStringType>(type) &&
2375 isa<moore::StringType>(value.getType())) {
2376 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2380 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2381 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2382 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2390 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2393 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2398 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2402 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
2403 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
2406 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
2408 return mlir::Float32Type::get(
builder.getContext());
2410 return mlir::Float64Type::get(
builder.getContext());
2414 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
2416 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
2418 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
2419 auto scale = moore::ConstantRealOp::create(
2420 builder, loc, value.getType(),
2422 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
2423 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
2424 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
2425 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
2429 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
2430 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
2431 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
2432 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
2433 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
2434 auto scale = moore::ConstantRealOp::create(
2437 return moore::DivRealOp::create(
builder, loc, asReal, scale);
2441 if (isa<moore::StringType>(type)) {
2442 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
2444 value = moore::LogicToIntOp::create(
builder, loc, value);
2445 return moore::IntToStringOp::create(
builder, loc, value);
2450 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2451 if (isa<moore::StringType>(value.getType())) {
2452 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
2456 return moore::IntToLogicOp::create(
builder, loc, value);
2463 if (isa<moore::FormatStringType>(type)) {
2465 value, isSigned, loc);
2468 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
2471 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
2472 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
2474 if (isa<moore::ClassHandleType>(type) &&
2475 isa<moore::ClassHandleType>(value.getType()))
2479 if (value.getType() != type)
2480 value = moore::ConversionOp::create(
builder, loc, type, value);
2488 auto systemCallRes =
2489 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2492 return moore::UrandomBIOp::create(
builder, loc,
nullptr);
2496 return moore::RandomBIOp::create(
builder, loc,
nullptr);
2500 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2503 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2506 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2507 .Default([&]() -> Value {
return {}; });
2508 return systemCallRes();
2513 Location loc, Value value) {
2514 auto systemCallRes =
2515 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2517 .Case(
"$signed", [&]() {
return value; })
2518 .Case(
"$unsigned", [&]() {
return value; })
2522 [&]() -> FailureOr<Value> {
2526 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
2530 return moore::LnBIOp::create(
builder, loc, value);
2534 return moore::Log10BIOp::create(
builder, loc, value);
2538 return moore::SinBIOp::create(
builder, loc, value);
2542 return moore::CosBIOp::create(
builder, loc, value);
2546 return moore::TanBIOp::create(
builder, loc, value);
2550 return moore::ExpBIOp::create(
builder, loc, value);
2554 return moore::SqrtBIOp::create(
builder, loc, value);
2558 return moore::FloorBIOp::create(
builder, loc, value);
2562 return moore::CeilBIOp::create(
builder, loc, value);
2566 return moore::AsinBIOp::create(
builder, loc, value);
2570 return moore::AcosBIOp::create(
builder, loc, value);
2574 return moore::AtanBIOp::create(
builder, loc, value);
2578 return moore::SinhBIOp::create(
builder, loc, value);
2582 return moore::CoshBIOp::create(
builder, loc, value);
2586 return moore::TanhBIOp::create(
builder, loc, value);
2590 return moore::AsinhBIOp::create(
builder, loc, value);
2594 return moore::AcoshBIOp::create(
builder, loc, value);
2598 return moore::AtanhBIOp::create(
builder, loc, value);
2602 return moore::UrandomBIOp::create(
builder, loc, value);
2606 return moore::RandomBIOp::create(
builder, loc, value);
2608 .Case(
"$realtobits",
2610 return moore::RealtobitsBIOp::create(
builder, loc, value);
2612 .Case(
"$bitstoreal",
2614 return moore::BitstorealBIOp::create(
builder, loc, value);
2616 .Case(
"$shortrealtobits",
2618 return moore::ShortrealtobitsBIOp::create(
builder, loc,
2621 .Case(
"$bitstoshortreal",
2623 return moore::BitstoshortrealBIOp::create(
builder, loc,
2628 if (isa<moore::StringType>(value.getType()))
2629 return moore::StringLenOp::create(
builder, loc, value);
2634 return moore::StringToUpperOp::create(
builder, loc, value);
2638 return moore::StringToLowerOp::create(
builder, loc, value);
2640 .Default([&]() -> Value {
return {}; });
2641 return systemCallRes();
2646 Location loc, Value value1, Value value2) {
2647 auto systemCallRes =
2648 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2651 return moore::StringGetCOp::create(
builder, loc, value1,
2654 .Default([&]() -> Value {
return {}; });
2655 return systemCallRes();
2660 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
2664 const moore::ClassHandleType &baseTy) {
2665 if (!actualTy || !baseTy)
2668 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
2669 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
2671 if (actualSym == baseSym)
2674 auto *op =
resolve(*
this, actualSym);
2675 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2678 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
2681 if (curBase == baseSym)
2683 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
2688moore::ClassHandleType
2690 llvm::StringRef fieldName, Location loc) {
2692 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
2696 auto *op =
resolve(*
this, classSym);
2697 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2702 for (
auto &block : decl.getBody()) {
2703 for (
auto &opInBlock : block) {
2705 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
2706 if (prop.getSymName() == fieldName) {
2708 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
2715 classSym = decl.getBaseAttr();
2719 mlir::emitError(loc) <<
"unknown property `" << fieldName <<
"`";
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Value materializeSBVToPackedConversion(Context &context, moore::PackedType packedType, Value value, Location loc)
Create the necessary operations to convert from a simple bit vector IntType to an equivalent PackedTy...
static mlir::Value maybeUpcastHandle(Context &context, mlir::Value actualHandle, moore::ClassHandleType expectedHandleTy)
Check whether the actual handle is a subclass of another handle type and return a properly upcast ver...
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
static Value visitClassProperty(Context &context, const slang::ast::ClassPropertySymbol &expr)
static uint64_t getTimeScaleInFemtoseconds(Context &context)
Get the currently active timescale as an integer number of femtoseconds.
static Value materializePackedToSBVConversion(Context &context, Value value, Location loc)
Create the necessary operations to convert from a PackedType to the corresponding simple bit vector I...
static Value getSelectIndex(Context &context, Location loc, Value index, const slang::ConstantRange &range)
Map an index into an array, with bounds range, to a bit offset of the underlying bit storage.
static FVInt convertSVIntToFVInt(const slang::SVInt &svint)
Convert a Slang SVInt to a CIRCT FVInt.
Four-valued arbitrary precision integers.
A packed SystemVerilog type.
bool containsTimeType() const
Check if this is a TimeType, or an aggregate that contains a nested TimeType.
IntType getSimpleBitVector() const
Get the simple bit vector type equivalent to this packed type.
Domain
The number of values each bit of a type can assume.
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
bool isIntType(Type type, unsigned width)
Check if a type is an IntType type of the given width.
@ f32
A standard 32-Bit floating point number ("float")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
Value materializeConversion(Type type, Value value, bool isSigned, Location loc)
Helper function to insert the necessary operations to cast a value from one type to another.
Value convertLvalueExpression(const slang::ast::Expression &expr)
Value materializeConstant(const slang::ConstantValue &constant, const slang::ast::Type &type, Location loc)
Helper function to materialize a ConstantValue as an SSA value.
slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr)
Evaluate the constant value of an expression.
slang::ast::Compilation & compilation
OpBuilder builder
The builder used to create IR operations.
Value materializeFixedSizeUnpackedArrayType(const slang::ConstantValue &constant, const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc)
Helper function to materialize an unpacked array of SVInts as an SSA value.
bool isClassDerivedFrom(const moore::ClassHandleType &actualTy, const moore::ClassHandleType &baseTy)
Checks whether one class (actualTy) is derived from another class (baseTy).
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
Value materializeSVInt(const slang::SVInt &svint, const slang::ast::Type &type, Location loc)
Helper function to materialize an SVInt as an SSA value.
Value materializeSVReal(const slang::ConstantValue &svreal, const slang::ast::Type &type, Location loc)
Helper function to materialize a real value as an SSA value.
Value convertToBool(Value value)
Helper function to convert a value to its "truthy" boolean value.
moore::ClassHandleType getAncestorClassWithProperty(const moore::ClassHandleType &actualTy, StringRef fieldName, Location loc)
Tries to find the closest base class of actualTy that carries a property with name fieldName.
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
FailureOr< Value > convertSystemCallArity0(const slang::ast::SystemSubroutine &subroutine, Location loc)
Convert system function calls only have arity-0.
Value convertToSimpleBitVector(Value value)
Helper function to convert a value to its simple bit vector representation, if it has one.
Value materializeString(const slang::ConstantValue &string, const slang::ast::Type &astType, Location loc)
Helper function to materialize a string as an SSA value.
FailureOr< Value > convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value)
Convert system function calls only have arity-1.
MLIRContext * getContext()
Return the MLIR context.
FailureOr< Value > convertSystemCallArity2(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value1, Value value2)
Convert system function calls with arity-2.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Function lowering information.
llvm::SmallVector< Value, 4 > captures