11#include "mlir/IR/Operation.h"
12#include "mlir/IR/Value.h"
13#include "slang/ast/EvalContext.h"
14#include "slang/ast/SystemSubroutine.h"
15#include "slang/ast/types/AllTypes.h"
16#include "slang/syntax/AllSyntax.h"
17#include "llvm/ADT/ScopeExit.h"
20using namespace ImportVerilog;
25 if (svint.hasUnknown()) {
26 unsigned numWords = svint.getNumWords() / 2;
27 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), numWords);
28 auto unknown = ArrayRef<uint64_t>(svint.getRawPtr() + numWords, numWords);
29 return FVInt(APInt(svint.getBitWidth(), value),
30 APInt(svint.getBitWidth(), unknown));
32 auto value = ArrayRef<uint64_t>(svint.getRawPtr(), svint.getNumWords());
33 return FVInt(APInt(svint.getBitWidth(), value));
40 const slang::ConstantRange &range) {
41 auto &builder =
context.builder;
42 auto indexType = cast<moore::UnpackedType>(index.getType());
45 auto lo = range.lower();
46 auto hi = range.upper();
47 auto offset = range.isLittleEndian() ? lo : hi;
50 const bool needSigned = (lo < 0) || (hi < 0);
53 const uint64_t maxAbs = std::max<uint64_t>(std::abs(lo), std::abs(hi));
58 unsigned want = needSigned
59 ? (llvm::Log2_64_Ceil(std::max<uint64_t>(1, maxAbs)) + 1)
60 : std::max<unsigned>(1, llvm::Log2_64_Ceil(maxAbs + 1));
63 const unsigned bw = std::max<unsigned>(want, indexType.getBitSize().value());
66 moore::IntType::get(index.getContext(), bw, indexType.getDomain());
67 index =
context.materializeConversion(intType, index, needSigned, loc);
70 if (range.isLittleEndian())
73 return moore::NegOp::create(builder, loc, index);
77 moore::ConstantOp::create(builder, loc, intType, offset, needSigned);
78 if (range.isLittleEndian())
79 return moore::SubOp::create(builder, loc, index, offsetConst);
81 return moore::SubOp::create(builder, loc, offsetConst, index);
86 static_assert(int(slang::TimeUnit::Seconds) == 0);
87 static_assert(int(slang::TimeUnit::Milliseconds) == 1);
88 static_assert(int(slang::TimeUnit::Microseconds) == 2);
89 static_assert(int(slang::TimeUnit::Nanoseconds) == 3);
90 static_assert(int(slang::TimeUnit::Picoseconds) == 4);
91 static_assert(int(slang::TimeUnit::Femtoseconds) == 5);
93 static_assert(int(slang::TimeScaleMagnitude::One) == 1);
94 static_assert(int(slang::TimeScaleMagnitude::Ten) == 10);
95 static_assert(int(slang::TimeScaleMagnitude::Hundred) == 100);
97 auto exp =
static_cast<unsigned>(
context.timeScale.base.unit);
100 auto scale =
static_cast<uint64_t
>(
context.timeScale.base.magnitude);
107 const slang::ast::ClassPropertySymbol &expr) {
108 auto loc =
context.convertLocation(expr.location);
109 auto builder =
context.builder;
110 auto type =
context.convertType(expr.getType());
111 auto fieldTy = cast<moore::UnpackedType>(type);
112 auto fieldRefTy = moore::RefType::get(fieldTy);
114 if (expr.lifetime == slang::ast::VariableLifetime::Static) {
117 if (!
context.globalVariables.lookup(&expr)) {
118 if (failed(
context.convertGlobalVariable(expr))) {
123 if (
auto globalOp =
context.globalVariables.lookup(&expr))
124 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
126 mlir::emitError(loc) <<
"Failed to access static member variable "
127 << expr.name <<
" as a global variable";
132 mlir::Value instRef =
context.getImplicitThisRef();
134 mlir::emitError(loc) <<
"class property '" << expr.name
135 <<
"' referenced without an implicit 'this'";
139 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(), expr.name);
141 moore::ClassHandleType classTy =
142 cast<moore::ClassHandleType>(instRef.getType());
144 auto targetClassHandle =
145 context.getAncestorClassWithProperty(classTy, expr.name, loc);
146 if (!targetClassHandle)
149 auto upcastRef =
context.materializeConversion(targetClassHandle, instRef,
150 false, instRef.getLoc());
154 Value fieldRef = moore::ClassPropertyRefOp::create(builder, loc, fieldRefTy,
155 upcastRef, fieldSym);
167 ExprVisitor(
Context &context, Location loc,
bool isLvalue)
168 : context(context), loc(loc), builder(context.builder),
169 isLvalue(isLvalue) {}
175 Value convertLvalueOrRvalueExpression(
const slang::ast::Expression &expr) {
182 Value visit(
const slang::ast::ElementSelectExpression &expr) {
184 auto value = convertLvalueOrRvalueExpression(expr.value());
189 auto derefType = value.getType();
191 derefType = cast<moore::RefType>(derefType).getNestedType();
193 if (!isa<moore::IntType, moore::ArrayType, moore::UnpackedArrayType,
194 moore::QueueType>(derefType)) {
195 mlir::emitError(loc) <<
"unsupported expression: element select into "
196 << expr.value().type->toString() <<
"\n";
201 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
202 auto range = expr.value().type->getFixedRange();
203 if (
auto *constValue = expr.selector().getConstant();
204 constValue && constValue->isInteger()) {
205 assert(!constValue->hasUnknown());
206 assert(constValue->size() <= 32);
208 auto lowBit = constValue->integer().as<uint32_t>().value();
210 return llvm::TypeSwitch<Type, Value>(derefType)
211 .Case<moore::QueueType>([&](moore::QueueType) {
213 <<
"Unexpected LValue extract on Queue Type!";
217 return moore::ExtractRefOp::create(builder, loc, resultType,
219 range.translateIndex(lowBit));
222 return llvm::TypeSwitch<Type, Value>(derefType)
223 .Case<moore::QueueType>([&](moore::QueueType) {
225 <<
"Unexpected RValue extract on Queue Type!";
229 return moore::ExtractOp::create(builder, loc, resultType, value,
230 range.translateIndex(lowBit));
239 return llvm::TypeSwitch<Type, Value>(derefType)
240 .Case<moore::QueueType>([&](moore::QueueType) {
241 return moore::DynQueueExtractRefOp::create(builder, loc, resultType,
245 return moore::DynExtractRefOp::create(builder, loc, resultType,
250 return llvm::TypeSwitch<Type, Value>(derefType)
251 .Case<moore::QueueType>([&](moore::QueueType) {
252 return moore::DynQueueExtractOp::create(builder, loc, resultType,
256 return moore::DynExtractOp::create(builder, loc, resultType, value,
263 Value visit(
const slang::ast::NullLiteral &expr) {
265 if (isa<moore::ClassHandleType, moore::ChandleType, moore::EventType,
266 moore::NullType>(type))
267 return moore::NullOp::create(builder, loc);
268 mlir::emitError(loc) <<
"No null value definition found for value of type "
274 Value visit(
const slang::ast::RangeSelectExpression &expr) {
276 auto value = convertLvalueOrRvalueExpression(expr.value());
280 std::optional<int32_t> constLeft;
281 std::optional<int32_t> constRight;
282 if (
auto *constant = expr.left().getConstant())
283 constLeft = constant->integer().as<int32_t>();
284 if (
auto *constant = expr.right().getConstant())
285 constRight = constant->integer().as<int32_t>();
291 <<
"unsupported expression: range select with non-constant bounds";
311 int32_t offsetConst = 0;
312 auto range = expr.value().type->getFixedRange();
314 using slang::ast::RangeSelectionKind;
315 if (expr.getSelectionKind() == RangeSelectionKind::Simple) {
320 assert(constRight &&
"constness checked in slang");
321 offsetConst = *constRight;
332 offsetConst = *constLeft;
343 int32_t offsetAdd = 0;
348 if (expr.getSelectionKind() == RangeSelectionKind::IndexedDown &&
349 range.isLittleEndian()) {
350 assert(constRight &&
"constness checked in slang");
351 offsetAdd = 1 - *constRight;
357 if (expr.getSelectionKind() == RangeSelectionKind::IndexedUp &&
358 !range.isLittleEndian()) {
359 assert(constRight &&
"constness checked in slang");
360 offsetAdd = *constRight - 1;
364 if (offsetAdd != 0) {
366 offsetDyn = moore::AddOp::create(
367 builder, loc, offsetDyn,
368 moore::ConstantOp::create(
369 builder, loc, cast<moore::IntType>(offsetDyn.getType()),
373 offsetConst += offsetAdd;
384 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type)) : type;
389 return moore::DynExtractRefOp::create(builder, loc, resultType, value,
392 return moore::DynExtractOp::create(builder, loc, resultType, value,
396 offsetConst = range.translateIndex(offsetConst);
398 return moore::ExtractRefOp::create(builder, loc, resultType, value,
401 return moore::ExtractOp::create(builder, loc, resultType, value,
408 Value visit(
const slang::ast::ConcatenationExpression &expr) {
409 SmallVector<Value> operands;
410 if (expr.type->isString()) {
411 for (
auto *operand : expr.operands()) {
412 assert(!isLvalue &&
"checked by Slang");
413 auto value = convertLvalueOrRvalueExpression(*operand);
417 moore::StringType::get(context.
getContext()), value,
false,
421 operands.push_back(value);
423 return moore::StringConcatOp::create(builder, loc, operands);
425 for (
auto *operand : expr.operands()) {
429 if (operand->type->isVoid())
431 auto value = convertLvalueOrRvalueExpression(*operand);
438 operands.push_back(value);
441 return moore::ConcatRefOp::create(builder, loc, operands);
443 return moore::ConcatOp::create(builder, loc, operands);
447 Value visit(
const slang::ast::MemberAccessExpression &expr) {
452 auto *valueType = expr.value().type.get();
453 auto memberName = builder.getStringAttr(expr.member.name);
456 if (valueType->isStruct()) {
458 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
460 auto value = convertLvalueOrRvalueExpression(expr.value());
465 return moore::StructExtractRefOp::create(builder, loc, resultType,
467 return moore::StructExtractOp::create(builder, loc, resultType,
472 if (valueType->isPackedUnion() || valueType->isUnpackedUnion()) {
474 isLvalue ? moore::RefType::get(cast<moore::UnpackedType>(type))
476 auto value = convertLvalueOrRvalueExpression(expr.value());
481 return moore::UnionExtractRefOp::create(builder, loc, resultType,
483 return moore::UnionExtractOp::create(builder, loc, type, memberName,
488 if (valueType->isClass()) {
492 auto targetTy = cast<moore::ClassHandleType>(valTy);
504 if (expr.member.kind != slang::ast::SymbolKind::Parameter) {
510 moore::ClassHandleType upcastTargetTy =
524 auto fieldSym = mlir::FlatSymbolRefAttr::get(builder.getContext(),
526 auto fieldRefTy = moore::RefType::get(cast<moore::UnpackedType>(type));
530 Value fieldRef = moore::ClassPropertyRefOp::create(
531 builder, loc, fieldRefTy, baseVal, fieldSym);
534 return isLvalue ? fieldRef
535 : moore::ReadOp::create(builder, loc, fieldRef);
538 slang::ConstantValue constVal;
539 if (
auto param = expr.member.as_if<slang::ast::ParameterSymbol>()) {
540 constVal = param->getValue();
545 mlir::emitError(loc) <<
"Parameter " << expr.member.name
546 <<
" has no constant value";
550 mlir::emitError(loc,
"expression of type ")
551 << valueType->toString() <<
" has no member fields";
563struct RvalueExprVisitor :
public ExprVisitor {
565 : ExprVisitor(
context, loc, false) {}
566 using ExprVisitor::visit;
569 Value visit(
const slang::ast::LValueReferenceExpression &expr) {
570 assert(!
context.lvalueStack.empty() &&
"parent assignments push lvalue");
571 auto lvalue =
context.lvalueStack.back();
572 return moore::ReadOp::create(builder, loc, lvalue);
576 Value visit(
const slang::ast::NamedValueExpression &expr) {
578 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
579 if (isa<moore::RefType>(value.getType())) {
580 auto readOp = moore::ReadOp::create(builder, loc, value);
581 if (
context.rvalueReadCallback)
582 context.rvalueReadCallback(readOp);
583 value = readOp.getResult();
589 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol)) {
590 auto value = moore::GetGlobalVariableOp::create(builder, loc, globalOp);
591 return moore::ReadOp::create(builder, loc, value);
595 if (
auto *
const property =
596 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
598 return moore::ReadOp::create(builder, loc, fieldRef).getResult();
602 auto constant =
context.evaluateConstant(expr);
603 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
608 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
609 d.attachNote(
context.convertLocation(expr.symbol.location))
610 <<
"no rvalue generated for " << slang::ast::toString(expr.symbol.kind);
615 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
616 auto hierLoc =
context.convertLocation(expr.symbol.location);
617 if (
auto value =
context.valueSymbols.lookup(&expr.symbol)) {
618 if (isa<moore::RefType>(value.getType())) {
619 auto readOp = moore::ReadOp::create(builder, hierLoc, value);
620 if (
context.rvalueReadCallback)
621 context.rvalueReadCallback(readOp);
622 value = readOp.getResult();
629 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
630 << expr.symbol.name <<
"`";
631 d.attachNote(hierLoc) <<
"no rvalue generated for "
632 << slang::ast::toString(expr.symbol.kind);
637 Value visit(
const slang::ast::ConversionExpression &expr) {
638 auto type =
context.convertType(*expr.type);
641 return context.convertRvalueExpression(expr.operand(), type);
645 Value visit(
const slang::ast::AssignmentExpression &expr) {
646 auto lhs =
context.convertLvalueExpression(expr.left());
651 context.lvalueStack.push_back(lhs);
652 auto rhs =
context.convertRvalueExpression(
653 expr.right(), cast<moore::RefType>(lhs.getType()).getNestedType());
654 context.lvalueStack.pop_back();
661 if (!expr.isNonBlocking()) {
662 if (expr.timingControl)
663 if (failed(
context.convertTimingControl(*expr.timingControl)))
665 auto assignOp = moore::BlockingAssignOp::create(builder, loc, lhs, rhs);
666 if (
context.variableAssignCallback)
667 context.variableAssignCallback(assignOp);
672 if (expr.timingControl) {
674 if (
auto *ctrl = expr.timingControl->as_if<slang::ast::DelayControl>()) {
675 auto delay =
context.convertRvalueExpression(
676 ctrl->expr, moore::TimeType::get(builder.getContext()));
679 auto assignOp = moore::DelayedNonBlockingAssignOp::create(
680 builder, loc, lhs, rhs, delay);
681 if (
context.variableAssignCallback)
682 context.variableAssignCallback(assignOp);
687 auto loc =
context.convertLocation(expr.timingControl->sourceRange);
689 <<
"unsupported non-blocking assignment timing control: "
690 << slang::ast::toString(expr.timingControl->kind);
693 auto assignOp = moore::NonBlockingAssignOp::create(builder, loc, lhs, rhs);
694 if (
context.variableAssignCallback)
695 context.variableAssignCallback(assignOp);
701 template <
class ConcreteOp>
702 Value createReduction(Value arg,
bool invert) {
703 arg =
context.convertToSimpleBitVector(arg);
706 Value result = ConcreteOp::create(builder, loc, arg);
708 result = moore::NotOp::create(builder, loc, result);
713 Value createIncrement(Value arg,
bool isInc,
bool isPost) {
714 auto preValue = moore::ReadOp::create(builder, loc, arg);
720 postValue = moore::NotOp::create(builder, loc, preValue).getResult();
723 auto one = moore::ConstantOp::create(
724 builder, loc, cast<moore::IntType>(preValue.getType()), 1);
726 isInc ? moore::AddOp::create(builder, loc, preValue, one).getResult()
727 : moore::SubOp::create(builder, loc, preValue, one).getResult();
729 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
730 if (
context.variableAssignCallback)
731 context.variableAssignCallback(assignOp);
740 Value createRealIncrement(Value arg,
bool isInc,
bool isPost) {
741 Value preValue = moore::ReadOp::create(builder, loc, arg);
744 bool isTime = isa<moore::TimeType>(preValue.getType());
746 preValue =
context.materializeConversion(
747 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
748 preValue,
false, loc);
750 moore::RealType realTy =
751 llvm::dyn_cast<moore::RealType>(preValue.getType());
756 if (realTy.getWidth() == moore::RealWidth::f32) {
757 oneAttr = builder.getFloatAttr(builder.getF32Type(), 1.0);
758 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
760 oneAttr = builder.getFloatAttr(builder.getF64Type(), oneVal);
762 mlir::emitError(loc) <<
"cannot construct increment for " << realTy;
765 auto one = moore::ConstantRealOp::create(builder, loc, oneAttr);
769 ? moore::AddRealOp::create(builder, loc, preValue, one).getResult()
770 : moore::SubRealOp::create(builder, loc, preValue, one).getResult();
773 postValue =
context.materializeConversion(
774 moore::TimeType::get(
context.getContext()), postValue,
false, loc);
777 moore::BlockingAssignOp::create(builder, loc, arg, postValue);
779 if (
context.variableAssignCallback)
780 context.variableAssignCallback(assignOp);
787 Value visitRealUOp(
const slang::ast::UnaryExpression &expr) {
788 Type opFTy =
context.convertType(*expr.operand().type);
790 using slang::ast::UnaryOperator;
792 if (expr.op == UnaryOperator::Preincrement ||
793 expr.op == UnaryOperator::Predecrement ||
794 expr.op == UnaryOperator::Postincrement ||
795 expr.op == UnaryOperator::Postdecrement)
796 arg =
context.convertLvalueExpression(expr.operand());
798 arg =
context.convertRvalueExpression(expr.operand(), opFTy);
803 if (isa<moore::TimeType>(arg.getType()))
804 arg =
context.materializeConversion(
805 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
810 case UnaryOperator::Plus:
812 case UnaryOperator::Minus:
813 return moore::NegRealOp::create(builder, loc, arg);
815 case UnaryOperator::Preincrement:
816 return createRealIncrement(arg,
true,
false);
817 case UnaryOperator::Predecrement:
818 return createRealIncrement(arg,
false,
false);
819 case UnaryOperator::Postincrement:
820 return createRealIncrement(arg,
true,
true);
821 case UnaryOperator::Postdecrement:
822 return createRealIncrement(arg,
false,
true);
824 case UnaryOperator::LogicalNot:
825 arg =
context.convertToBool(arg);
828 return moore::NotOp::create(builder, loc, arg);
831 mlir::emitError(loc) <<
"Unary operator " << slang::ast::toString(expr.op)
832 <<
" not supported with real values!\n";
838 Value visit(
const slang::ast::UnaryExpression &expr) {
840 const auto *floatType =
841 expr.operand().type->as_if<slang::ast::FloatingType>();
844 return visitRealUOp(expr);
846 using slang::ast::UnaryOperator;
848 if (expr.op == UnaryOperator::Preincrement ||
849 expr.op == UnaryOperator::Predecrement ||
850 expr.op == UnaryOperator::Postincrement ||
851 expr.op == UnaryOperator::Postdecrement)
852 arg =
context.convertLvalueExpression(expr.operand());
854 arg =
context.convertRvalueExpression(expr.operand());
861 case UnaryOperator::Plus:
862 return context.convertToSimpleBitVector(arg);
864 case UnaryOperator::Minus:
865 arg =
context.convertToSimpleBitVector(arg);
868 return moore::NegOp::create(builder, loc, arg);
870 case UnaryOperator::BitwiseNot:
871 arg =
context.convertToSimpleBitVector(arg);
874 return moore::NotOp::create(builder, loc, arg);
876 case UnaryOperator::BitwiseAnd:
877 return createReduction<moore::ReduceAndOp>(arg,
false);
878 case UnaryOperator::BitwiseOr:
879 return createReduction<moore::ReduceOrOp>(arg,
false);
880 case UnaryOperator::BitwiseXor:
881 return createReduction<moore::ReduceXorOp>(arg,
false);
882 case UnaryOperator::BitwiseNand:
883 return createReduction<moore::ReduceAndOp>(arg,
true);
884 case UnaryOperator::BitwiseNor:
885 return createReduction<moore::ReduceOrOp>(arg,
true);
886 case UnaryOperator::BitwiseXnor:
887 return createReduction<moore::ReduceXorOp>(arg,
true);
889 case UnaryOperator::LogicalNot:
890 arg =
context.convertToBool(arg);
893 return moore::NotOp::create(builder, loc, arg);
895 case UnaryOperator::Preincrement:
896 return createIncrement(arg,
true,
false);
897 case UnaryOperator::Predecrement:
898 return createIncrement(arg,
false,
false);
899 case UnaryOperator::Postincrement:
900 return createIncrement(arg,
true,
true);
901 case UnaryOperator::Postdecrement:
902 return createIncrement(arg,
false,
true);
905 mlir::emitError(loc,
"unsupported unary operator");
910 Value buildLogicalBOp(slang::ast::BinaryOperator op, Value lhs, Value rhs,
911 std::optional<Domain> domain = std::nullopt) {
912 using slang::ast::BinaryOperator;
916 lhs =
context.convertToBool(lhs, domain.value());
917 rhs =
context.convertToBool(rhs, domain.value());
919 lhs =
context.convertToBool(lhs);
920 rhs =
context.convertToBool(rhs);
927 case BinaryOperator::LogicalAnd:
928 return moore::AndOp::create(builder, loc, lhs, rhs);
930 case BinaryOperator::LogicalOr:
931 return moore::OrOp::create(builder, loc, lhs, rhs);
933 case BinaryOperator::LogicalImplication: {
935 auto notLHS = moore::NotOp::create(builder, loc, lhs);
936 return moore::OrOp::create(builder, loc, notLHS, rhs);
939 case BinaryOperator::LogicalEquivalence: {
941 auto notLHS = moore::NotOp::create(builder, loc, lhs);
942 auto notRHS = moore::NotOp::create(builder, loc, rhs);
943 auto both = moore::AndOp::create(builder, loc, lhs, rhs);
944 auto notBoth = moore::AndOp::create(builder, loc, notLHS, notRHS);
945 return moore::OrOp::create(builder, loc, both, notBoth);
949 llvm_unreachable(
"not a logical BinaryOperator");
953 Value visitHandleBOp(
const slang::ast::BinaryExpression &expr) {
955 auto lhs =
context.convertRvalueExpression(expr.left());
958 auto rhs =
context.convertRvalueExpression(expr.right());
962 using slang::ast::BinaryOperator;
965 case BinaryOperator::Equality:
966 return moore::HandleEqOp::create(builder, loc, lhs, rhs);
967 case BinaryOperator::Inequality:
968 return moore::HandleNeOp::create(builder, loc, lhs, rhs);
969 case BinaryOperator::CaseEquality:
970 return moore::HandleCaseEqOp::create(builder, loc, lhs, rhs);
971 case BinaryOperator::CaseInequality:
972 return moore::HandleCaseNeOp::create(builder, loc, lhs, rhs);
976 <<
"Binary operator " << slang::ast::toString(expr.op)
977 <<
" not supported with class handle valued operands!\n";
982 Value visitRealBOp(
const slang::ast::BinaryExpression &expr) {
984 auto lhs =
context.convertRvalueExpression(expr.left());
987 auto rhs =
context.convertRvalueExpression(expr.right());
991 if (isa<moore::TimeType>(lhs.getType()) ||
992 isa<moore::TimeType>(rhs.getType())) {
993 lhs =
context.materializeConversion(
994 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
996 rhs =
context.materializeConversion(
997 moore::RealType::get(
context.getContext(), moore::RealWidth::f64),
1001 using slang::ast::BinaryOperator;
1003 case BinaryOperator::Add:
1004 return moore::AddRealOp::create(builder, loc, lhs, rhs);
1005 case BinaryOperator::Subtract:
1006 return moore::SubRealOp::create(builder, loc, lhs, rhs);
1007 case BinaryOperator::Multiply:
1008 return moore::MulRealOp::create(builder, loc, lhs, rhs);
1009 case BinaryOperator::Divide:
1010 return moore::DivRealOp::create(builder, loc, lhs, rhs);
1011 case BinaryOperator::Power:
1012 return moore::PowRealOp::create(builder, loc, lhs, rhs);
1014 case BinaryOperator::Equality:
1015 return moore::EqRealOp::create(builder, loc, lhs, rhs);
1016 case BinaryOperator::Inequality:
1017 return moore::NeRealOp::create(builder, loc, lhs, rhs);
1019 case BinaryOperator::GreaterThan:
1020 return moore::FgtOp::create(builder, loc, lhs, rhs);
1021 case BinaryOperator::LessThan:
1022 return moore::FltOp::create(builder, loc, lhs, rhs);
1023 case BinaryOperator::GreaterThanEqual:
1024 return moore::FgeOp::create(builder, loc, lhs, rhs);
1025 case BinaryOperator::LessThanEqual:
1026 return moore::FleOp::create(builder, loc, lhs, rhs);
1028 case BinaryOperator::LogicalAnd:
1029 case BinaryOperator::LogicalOr:
1030 case BinaryOperator::LogicalImplication:
1031 case BinaryOperator::LogicalEquivalence:
1032 return buildLogicalBOp(expr.op, lhs, rhs);
1035 mlir::emitError(loc) <<
"Binary operator "
1036 << slang::ast::toString(expr.op)
1037 <<
" not supported with real valued operands!\n";
1044 template <
class ConcreteOp>
1045 Value createBinary(Value lhs, Value rhs) {
1046 lhs =
context.convertToSimpleBitVector(lhs);
1049 rhs =
context.convertToSimpleBitVector(rhs);
1052 return ConcreteOp::create(builder, loc, lhs, rhs);
1056 Value visit(
const slang::ast::BinaryExpression &expr) {
1058 const auto *rhsFloatType =
1059 expr.right().type->as_if<slang::ast::FloatingType>();
1060 const auto *lhsFloatType =
1061 expr.left().type->as_if<slang::ast::FloatingType>();
1064 if (rhsFloatType || lhsFloatType)
1065 return visitRealBOp(expr);
1068 const auto rhsIsClass = expr.right().type->isClass();
1069 const auto lhsIsClass = expr.left().type->isClass();
1070 const auto rhsIsChandle = expr.right().type->isCHandle();
1071 const auto lhsIsChandle = expr.left().type->isCHandle();
1073 if (rhsIsClass || lhsIsClass || rhsIsChandle || lhsIsChandle)
1074 return visitHandleBOp(expr);
1076 auto lhs =
context.convertRvalueExpression(expr.left());
1079 auto rhs =
context.convertRvalueExpression(expr.right());
1084 Domain domain = Domain::TwoValued;
1085 if (expr.type->isFourState() || expr.left().type->isFourState() ||
1086 expr.right().type->isFourState())
1087 domain = Domain::FourValued;
1089 using slang::ast::BinaryOperator;
1091 case BinaryOperator::Add:
1092 return createBinary<moore::AddOp>(lhs, rhs);
1093 case BinaryOperator::Subtract:
1094 return createBinary<moore::SubOp>(lhs, rhs);
1095 case BinaryOperator::Multiply:
1096 return createBinary<moore::MulOp>(lhs, rhs);
1097 case BinaryOperator::Divide:
1098 if (expr.type->isSigned())
1099 return createBinary<moore::DivSOp>(lhs, rhs);
1101 return createBinary<moore::DivUOp>(lhs, rhs);
1102 case BinaryOperator::Mod:
1103 if (expr.type->isSigned())
1104 return createBinary<moore::ModSOp>(lhs, rhs);
1106 return createBinary<moore::ModUOp>(lhs, rhs);
1107 case BinaryOperator::Power: {
1112 auto rhsCast =
context.materializeConversion(
1113 lhs.getType(), rhs, expr.right().type->isSigned(), rhs.getLoc());
1114 if (expr.type->isSigned())
1115 return createBinary<moore::PowSOp>(lhs, rhsCast);
1117 return createBinary<moore::PowUOp>(lhs, rhsCast);
1120 case BinaryOperator::BinaryAnd:
1121 return createBinary<moore::AndOp>(lhs, rhs);
1122 case BinaryOperator::BinaryOr:
1123 return createBinary<moore::OrOp>(lhs, rhs);
1124 case BinaryOperator::BinaryXor:
1125 return createBinary<moore::XorOp>(lhs, rhs);
1126 case BinaryOperator::BinaryXnor: {
1127 auto result = createBinary<moore::XorOp>(lhs, rhs);
1130 return moore::NotOp::create(builder, loc, result);
1133 case BinaryOperator::Equality:
1134 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1135 return moore::UArrayCmpOp::create(
1136 builder, loc, moore::UArrayCmpPredicate::eq, lhs, rhs);
1137 else if (isa<moore::StringType>(lhs.getType()))
1138 return moore::StringCmpOp::create(
1139 builder, loc, moore::StringCmpPredicate::eq, lhs, rhs);
1141 return createBinary<moore::EqOp>(lhs, rhs);
1142 case BinaryOperator::Inequality:
1143 if (isa<moore::UnpackedArrayType>(lhs.getType()))
1144 return moore::UArrayCmpOp::create(
1145 builder, loc, moore::UArrayCmpPredicate::ne, lhs, rhs);
1146 else if (isa<moore::StringType>(lhs.getType()))
1147 return moore::StringCmpOp::create(
1148 builder, loc, moore::StringCmpPredicate::ne, lhs, rhs);
1150 return createBinary<moore::NeOp>(lhs, rhs);
1151 case BinaryOperator::CaseEquality:
1152 return createBinary<moore::CaseEqOp>(lhs, rhs);
1153 case BinaryOperator::CaseInequality:
1154 return createBinary<moore::CaseNeOp>(lhs, rhs);
1155 case BinaryOperator::WildcardEquality:
1156 return createBinary<moore::WildcardEqOp>(lhs, rhs);
1157 case BinaryOperator::WildcardInequality:
1158 return createBinary<moore::WildcardNeOp>(lhs, rhs);
1160 case BinaryOperator::GreaterThanEqual:
1161 if (expr.left().type->isSigned())
1162 return createBinary<moore::SgeOp>(lhs, rhs);
1163 else if (isa<moore::StringType>(lhs.getType()))
1164 return moore::StringCmpOp::create(
1165 builder, loc, moore::StringCmpPredicate::ge, lhs, rhs);
1167 return createBinary<moore::UgeOp>(lhs, rhs);
1168 case BinaryOperator::GreaterThan:
1169 if (expr.left().type->isSigned())
1170 return createBinary<moore::SgtOp>(lhs, rhs);
1171 else if (isa<moore::StringType>(lhs.getType()))
1172 return moore::StringCmpOp::create(
1173 builder, loc, moore::StringCmpPredicate::gt, lhs, rhs);
1175 return createBinary<moore::UgtOp>(lhs, rhs);
1176 case BinaryOperator::LessThanEqual:
1177 if (expr.left().type->isSigned())
1178 return createBinary<moore::SleOp>(lhs, rhs);
1179 else if (isa<moore::StringType>(lhs.getType()))
1180 return moore::StringCmpOp::create(
1181 builder, loc, moore::StringCmpPredicate::le, lhs, rhs);
1183 return createBinary<moore::UleOp>(lhs, rhs);
1184 case BinaryOperator::LessThan:
1185 if (expr.left().type->isSigned())
1186 return createBinary<moore::SltOp>(lhs, rhs);
1187 else if (isa<moore::StringType>(lhs.getType()))
1188 return moore::StringCmpOp::create(
1189 builder, loc, moore::StringCmpPredicate::lt, lhs, rhs);
1191 return createBinary<moore::UltOp>(lhs, rhs);
1193 case BinaryOperator::LogicalAnd:
1194 case BinaryOperator::LogicalOr:
1195 case BinaryOperator::LogicalImplication:
1196 case BinaryOperator::LogicalEquivalence:
1197 return buildLogicalBOp(expr.op, lhs, rhs, domain);
1199 case BinaryOperator::LogicalShiftLeft:
1200 return createBinary<moore::ShlOp>(lhs, rhs);
1201 case BinaryOperator::LogicalShiftRight:
1202 return createBinary<moore::ShrOp>(lhs, rhs);
1203 case BinaryOperator::ArithmeticShiftLeft:
1204 return createBinary<moore::ShlOp>(lhs, rhs);
1205 case BinaryOperator::ArithmeticShiftRight: {
1208 lhs =
context.convertToSimpleBitVector(lhs);
1209 rhs =
context.convertToSimpleBitVector(rhs);
1212 if (expr.type->isSigned())
1213 return moore::AShrOp::create(builder, loc, lhs, rhs);
1214 return moore::ShrOp::create(builder, loc, lhs, rhs);
1218 mlir::emitError(loc,
"unsupported binary operator");
1223 Value visit(
const slang::ast::UnbasedUnsizedIntegerLiteral &expr) {
1224 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1228 Value visit(
const slang::ast::IntegerLiteral &expr) {
1229 return context.materializeSVInt(expr.getValue(), *expr.type, loc);
1233 Value visit(
const slang::ast::TimeLiteral &expr) {
1238 double value = std::round(expr.getValue() * scale);
1248 static constexpr uint64_t limit =
1249 (std::numeric_limits<uint64_t>::max() >> 11) << 11;
1250 if (value > limit) {
1251 mlir::emitError(loc) <<
"time value is larger than " << limit <<
" fs";
1255 return moore::ConstantTimeOp::create(builder, loc,
1256 static_cast<uint64_t
>(value));
1260 Value visit(
const slang::ast::ReplicationExpression &expr) {
1261 auto type =
context.convertType(*expr.type);
1262 auto value =
context.convertRvalueExpression(expr.concat());
1265 return moore::ReplicateOp::create(builder, loc, type, value);
1269 Value visit(
const slang::ast::InsideExpression &expr) {
1270 auto lhs =
context.convertToSimpleBitVector(
1271 context.convertRvalueExpression(expr.left()));
1275 SmallVector<Value> conditions;
1278 for (
const auto *listExpr : expr.rangeList()) {
1282 if (
const auto *openRange =
1283 listExpr->as_if<slang::ast::ValueRangeExpression>()) {
1285 auto lowBound =
context.convertToSimpleBitVector(
1286 context.convertRvalueExpression(openRange->left()));
1287 auto highBound =
context.convertToSimpleBitVector(
1288 context.convertRvalueExpression(openRange->right()));
1289 if (!lowBound || !highBound)
1291 Value leftValue, rightValue;
1294 if (openRange->left().type->isSigned() ||
1295 expr.left().type->isSigned()) {
1296 leftValue = moore::SgeOp::create(builder, loc, lhs, lowBound);
1298 leftValue = moore::UgeOp::create(builder, loc, lhs, lowBound);
1300 if (openRange->right().type->isSigned() ||
1301 expr.left().type->isSigned()) {
1302 rightValue = moore::SleOp::create(builder, loc, lhs, highBound);
1304 rightValue = moore::UleOp::create(builder, loc, lhs, highBound);
1306 cond = moore::AndOp::create(builder, loc, leftValue, rightValue);
1309 if (!listExpr->type->isIntegral()) {
1310 if (listExpr->type->isUnpackedArray()) {
1312 loc,
"unpacked arrays in 'inside' expressions not supported");
1316 loc,
"only simple bit vectors supported in 'inside' expressions");
1320 auto value =
context.convertToSimpleBitVector(
1321 context.convertRvalueExpression(*listExpr));
1324 cond = moore::WildcardEqOp::create(builder, loc, lhs, value);
1326 conditions.push_back(cond);
1330 auto result = conditions.back();
1331 conditions.pop_back();
1332 while (!conditions.empty()) {
1333 result = moore::OrOp::create(builder, loc, conditions.back(), result);
1334 conditions.pop_back();
1340 Value visit(
const slang::ast::ConditionalExpression &expr) {
1341 auto type =
context.convertType(*expr.type);
1344 if (expr.conditions.size() > 1) {
1345 mlir::emitError(loc)
1346 <<
"unsupported conditional expression with more than one condition";
1349 const auto &cond = expr.conditions[0];
1351 mlir::emitError(loc) <<
"unsupported conditional expression with pattern";
1355 context.convertToBool(
context.convertRvalueExpression(*cond.expr));
1358 auto conditionalOp =
1359 moore::ConditionalOp::create(builder, loc, type, value);
1362 auto &trueBlock = conditionalOp.getTrueRegion().emplaceBlock();
1363 auto &falseBlock = conditionalOp.getFalseRegion().emplaceBlock();
1365 OpBuilder::InsertionGuard g(builder);
1368 builder.setInsertionPointToStart(&trueBlock);
1369 auto trueValue =
context.convertRvalueExpression(expr.left(), type);
1372 moore::YieldOp::create(builder, loc, trueValue);
1375 builder.setInsertionPointToStart(&falseBlock);
1376 auto falseValue =
context.convertRvalueExpression(expr.right(), type);
1379 moore::YieldOp::create(builder, loc, falseValue);
1381 return conditionalOp.getResult();
1385 Value visit(
const slang::ast::CallExpression &expr) {
1387 auto constant =
context.evaluateConstant(expr);
1388 if (
auto value =
context.materializeConstant(constant, *expr.type, loc))
1392 [&](
auto &subroutine) {
return visitCall(expr, subroutine); },
1398 std::pair<Value, moore::ClassHandleType>
1399 getMethodReceiverTypeHandle(
const slang::ast::CallExpression &expr) {
1401 moore::ClassHandleType handleTy;
1405 if (
const slang::ast::Expression *recvExpr = expr.thisClass()) {
1406 thisRef =
context.convertRvalueExpression(*recvExpr);
1411 thisRef =
context.getImplicitThisRef();
1413 mlir::emitError(loc) <<
"method '" << expr.getSubroutineName()
1414 <<
"' called without an object";
1418 handleTy = cast<moore::ClassHandleType>(thisRef.getType());
1419 return {thisRef, handleTy};
1423 mlir::CallOpInterface
1424 buildMethodCall(
const slang::ast::SubroutineSymbol *subroutine,
1426 moore::ClassHandleType actualHandleTy, Value actualThisRef,
1427 SmallVector<Value> &arguments,
1428 SmallVector<Type> &resultTypes) {
1431 auto funcTy = lowering->
op.getFunctionType();
1432 auto expected0 = funcTy.getInput(0);
1433 auto expectedHdlTy = cast<moore::ClassHandleType>(expected0);
1436 auto implicitThisRef =
context.materializeConversion(
1437 expectedHdlTy, actualThisRef,
false, actualThisRef.getLoc());
1440 SmallVector<Value> explicitArguments;
1441 explicitArguments.reserve(arguments.size() + 1);
1442 explicitArguments.push_back(implicitThisRef);
1443 explicitArguments.append(arguments.begin(), arguments.end());
1446 const bool isVirtual =
1447 (subroutine->flags & slang::ast::MethodFlags::Virtual) != 0;
1450 auto calleeSym = lowering->
op.getSymName();
1452 return mlir::func::CallOp::create(builder, loc, resultTypes, calleeSym,
1456 auto funcName = subroutine->name;
1457 auto method = moore::VTableLoadMethodOp::create(
1458 builder, loc, funcTy, actualThisRef,
1459 SymbolRefAttr::get(
context.getContext(), funcName));
1460 return mlir::func::CallIndirectOp::create(builder, loc, method,
1465 Value visitCall(
const slang::ast::CallExpression &expr,
1466 const slang::ast::SubroutineSymbol *subroutine) {
1468 const bool isMethod = (subroutine->thisVar !=
nullptr);
1470 auto *lowering =
context.declareFunction(*subroutine);
1473 auto convertedFunction =
context.convertFunction(*subroutine);
1474 if (failed(convertedFunction))
1480 SmallVector<Value> arguments;
1481 for (
auto [callArg, declArg] :
1482 llvm::zip(expr.arguments(), subroutine->getArguments())) {
1486 auto *expr = callArg;
1487 if (
const auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
1488 expr = &assign->left();
1491 auto type =
context.convertType(declArg->getType());
1492 if (declArg->direction == slang::ast::ArgumentDirection::In) {
1493 value =
context.convertRvalueExpression(*expr, type);
1495 Value lvalue =
context.convertLvalueExpression(*expr);
1496 auto unpackedType = dyn_cast<moore::UnpackedType>(type);
1500 context.materializeConversion(moore::RefType::get(unpackedType),
1501 lvalue, expr->type->isSigned(), loc);
1505 arguments.push_back(value);
1509 auto materializeCaptureAtCall = [&](Value cap) -> Value {
1511 auto refTy = dyn_cast<moore::RefType>(cap.getType());
1513 lowering->
op.emitError(
1514 "expected captured value to be moore::RefType");
1521 Region *capRegion = [&]() -> Region * {
1522 if (
auto ba = dyn_cast<BlockArgument>(cap))
1523 return ba.getOwner()->getParent();
1524 if (
auto *def = cap.getDefiningOp())
1525 return def->getParentRegion();
1529 Region *callRegion =
1530 builder.getBlock() ? builder.getBlock()->getParent() :
nullptr;
1532 for (Region *r = callRegion; r; r = r->getParentRegion()) {
1533 if (r == capRegion) {
1540 lowering->
op.emitError()
1541 <<
"cannot materialize captured ref at call site; non-symbol "
1543 << (cap.getDefiningOp()
1544 ? cap.getDefiningOp()->getName().getStringRef()
1549 for (Value cap : lowering->captures) {
1550 Value mat = materializeCaptureAtCall(cap);
1553 arguments.push_back(mat);
1558 SmallVector<Type> resultTypes(
1559 lowering->
op.getFunctionType().getResults().begin(),
1560 lowering->
op.getFunctionType().getResults().end());
1562 mlir::CallOpInterface callOp;
1566 auto [thisRef, tyHandle] = getMethodReceiverTypeHandle(expr);
1567 callOp = buildMethodCall(subroutine, lowering, tyHandle, thisRef,
1568 arguments, resultTypes);
1572 mlir::func::CallOp::create(builder, loc, lowering->
op, arguments);
1575 auto result = resultTypes.size() > 0 ? callOp->getOpResult(0) : Value{};
1579 if (resultTypes.size() == 0)
1580 return mlir::UnrealizedConversionCastOp::create(
1581 builder, loc, moore::VoidType::get(
context.getContext()),
1589 Value visitCall(
const slang::ast::CallExpression &expr,
1590 const slang::ast::CallExpression::SystemCallInfo &info) {
1591 const auto &subroutine = *
info.subroutine;
1596 bool isAssertionCall = llvm::StringSwitch<bool>(subroutine.name)
1597 .Cases({
"$rose",
"$fell",
"$stable",
"$changed",
1598 "$past",
"$sampled"},
1602 if (isAssertionCall)
1603 return context.convertAssertionCallExpression(expr, info, loc);
1605 auto args = expr.arguments();
1607 FailureOr<Value> result = Value{};
1617 if (!subroutine.name.compare(
"$sformatf")) {
1619 auto fmtValue =
context.convertFormatString(
1620 expr.arguments(), loc, moore::IntFormat::Decimal,
false);
1621 if (failed(fmtValue))
1623 return fmtValue.value();
1627 bool isByRefOp = args.size() >= 1 && args[0]->type->isQueue();
1635 switch (args.size()) {
1637 result =
context.convertSystemCallArity0(subroutine, loc);
1641 value = isByRefOp ?
context.convertLvalueExpression(*args[0])
1642 :
context.convertRvalueExpression(*args[0]);
1645 result =
context.convertSystemCallArity1(subroutine, loc, value);
1649 value = isByRefOp ?
context.convertLvalueExpression(*args[0])
1650 :
context.convertRvalueExpression(*args[0]);
1651 value2 =
context.convertRvalueExpression(*args[1]);
1652 if (!value || !value2)
1654 result =
context.convertSystemCallArity2(subroutine, loc, value, value2);
1670 auto ty =
context.convertType(*expr.type);
1671 return context.materializeConversion(ty, *result, expr.type->isSigned(),
1676 mlir::emitError(loc) <<
"unsupported system call `" << subroutine.name
1682 Value visit(
const slang::ast::StringLiteral &expr) {
1683 auto type =
context.convertType(*expr.type);
1684 return moore::ConstantStringOp::create(builder, loc, type, expr.getValue());
1688 Value visit(
const slang::ast::RealLiteral &expr) {
1689 auto fTy = mlir::Float64Type::get(
context.getContext());
1690 auto attr = mlir::FloatAttr::get(fTy, expr.getValue());
1691 return moore::ConstantRealOp::create(builder, loc, attr).getResult();
1696 FailureOr<SmallVector<Value>>
1697 convertElements(
const slang::ast::AssignmentPatternExpressionBase &expr,
1698 std::variant<Type, ArrayRef<Type>> expectedTypes,
1699 unsigned replCount) {
1700 const auto &elts = expr.elements();
1701 const size_t elementCount = elts.size();
1704 const bool hasBroadcast =
1705 std::holds_alternative<Type>(expectedTypes) &&
1706 static_cast<bool>(std::get<Type>(expectedTypes));
1708 const bool hasPerElem =
1709 std::holds_alternative<ArrayRef<Type>>(expectedTypes) &&
1710 !std::get<ArrayRef<Type>>(expectedTypes).empty();
1714 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1715 if (types.size() != elementCount) {
1716 mlir::emitError(loc)
1717 <<
"assignment pattern arity mismatch: expected " << types.size()
1718 <<
" elements, got " << elementCount;
1723 SmallVector<Value> converted;
1724 converted.reserve(elementCount * std::max(1u, replCount));
1727 if (!hasBroadcast && !hasPerElem) {
1729 for (
const auto *elementExpr : elts) {
1730 Value v =
context.convertRvalueExpression(*elementExpr);
1733 converted.push_back(v);
1735 }
else if (hasBroadcast) {
1737 Type want = std::get<Type>(expectedTypes);
1738 for (
const auto *elementExpr : elts) {
1739 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1740 :
context.convertRvalueExpression(*elementExpr);
1743 converted.push_back(v);
1746 auto types = std::get<ArrayRef<Type>>(expectedTypes);
1747 for (
size_t i = 0; i < elementCount; ++i) {
1748 Type want = types[i];
1749 const auto *elementExpr = elts[i];
1750 Value v = want ?
context.convertRvalueExpression(*elementExpr, want)
1751 :
context.convertRvalueExpression(*elementExpr);
1754 converted.push_back(v);
1758 for (
unsigned i = 1; i < replCount; ++i)
1759 converted.append(converted.begin(), converted.begin() + elementCount);
1765 Value visitAssignmentPattern(
1766 const slang::ast::AssignmentPatternExpressionBase &expr,
1767 unsigned replCount = 1) {
1768 auto type =
context.convertType(*expr.type);
1769 const auto &elts = expr.elements();
1772 if (
auto intType = dyn_cast<moore::IntType>(type)) {
1773 auto elements = convertElements(expr, {}, replCount);
1775 if (failed(elements))
1778 assert(intType.getWidth() == elements->size());
1779 std::reverse(elements->begin(), elements->end());
1780 return moore::ConcatOp::create(builder, loc, intType, *elements);
1784 if (
auto structType = dyn_cast<moore::StructType>(type)) {
1785 SmallVector<Type> expectedTy;
1786 expectedTy.reserve(structType.getMembers().size());
1787 for (
auto member : structType.getMembers())
1788 expectedTy.push_back(member.type);
1790 FailureOr<SmallVector<Value>> elements;
1791 if (expectedTy.size() == elts.size())
1792 elements = convertElements(expr, expectedTy, replCount);
1794 elements = convertElements(expr, {}, replCount);
1796 if (failed(elements))
1799 assert(structType.getMembers().size() == elements->size());
1800 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1804 if (
auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
1805 SmallVector<Type> expectedTy;
1806 expectedTy.reserve(structType.getMembers().size());
1807 for (
auto member : structType.getMembers())
1808 expectedTy.push_back(member.type);
1810 FailureOr<SmallVector<Value>> elements;
1811 if (expectedTy.size() == elts.size())
1812 elements = convertElements(expr, expectedTy, replCount);
1814 elements = convertElements(expr, {}, replCount);
1816 if (failed(elements))
1819 assert(structType.getMembers().size() == elements->size());
1821 return moore::StructCreateOp::create(builder, loc, structType, *elements);
1825 if (
auto arrayType = dyn_cast<moore::ArrayType>(type)) {
1827 convertElements(expr, arrayType.getElementType(), replCount);
1829 if (failed(elements))
1832 assert(arrayType.getSize() == elements->size());
1833 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1837 if (
auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
1839 convertElements(expr, arrayType.getElementType(), replCount);
1841 if (failed(elements))
1844 assert(arrayType.getSize() == elements->size());
1845 return moore::ArrayCreateOp::create(builder, loc, arrayType, *elements);
1848 mlir::emitError(loc) <<
"unsupported assignment pattern with type " << type;
1852 Value visit(
const slang::ast::SimpleAssignmentPatternExpression &expr) {
1853 return visitAssignmentPattern(expr);
1856 Value visit(
const slang::ast::StructuredAssignmentPatternExpression &expr) {
1857 return visitAssignmentPattern(expr);
1860 Value visit(
const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
1862 context.evaluateConstant(expr.count()).integer().as<
unsigned>();
1863 assert(count &&
"Slang guarantees constant non-zero replication count");
1864 return visitAssignmentPattern(expr, *count);
1867 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
1868 SmallVector<Value> operands;
1869 for (
auto stream : expr.streams()) {
1870 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
1871 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1872 mlir::emitError(operandLoc)
1873 <<
"Moore only support streaming "
1874 "concatenation with fixed size 'with expression'";
1878 if (stream.constantWithWidth.has_value()) {
1879 value =
context.convertRvalueExpression(*stream.withExpr);
1880 auto type = cast<moore::UnpackedType>(value.getType());
1881 auto intType = moore::IntType::get(
1882 context.getContext(), type.getBitSize().value(), type.getDomain());
1884 value =
context.materializeConversion(intType, value,
false, loc);
1886 value =
context.convertRvalueExpression(*stream.operand);
1889 value =
context.convertToSimpleBitVector(value);
1892 operands.push_back(value);
1896 if (operands.size() == 1) {
1899 value = operands.front();
1901 value = moore::ConcatOp::create(builder, loc, operands).getResult();
1904 if (expr.getSliceSize() == 0) {
1908 auto type = cast<moore::IntType>(value.getType());
1909 SmallVector<Value> slicedOperands;
1910 auto iterMax = type.getWidth() / expr.getSliceSize();
1911 auto remainSize = type.getWidth() % expr.getSliceSize();
1913 for (
size_t i = 0; i < iterMax; i++) {
1914 auto extractResultType = moore::IntType::get(
1915 context.getContext(), expr.getSliceSize(), type.getDomain());
1917 auto extracted = moore::ExtractOp::create(builder, loc, extractResultType,
1918 value, i * expr.getSliceSize());
1919 slicedOperands.push_back(extracted);
1923 auto extractResultType = moore::IntType::get(
1924 context.getContext(), remainSize, type.getDomain());
1927 moore::ExtractOp::create(builder, loc, extractResultType, value,
1928 iterMax * expr.getSliceSize());
1929 slicedOperands.push_back(extracted);
1932 return moore::ConcatOp::create(builder, loc, slicedOperands);
1935 Value visit(
const slang::ast::AssertionInstanceExpression &expr) {
1936 return context.convertAssertionExpression(expr.body, loc);
1951 Value visit(
const slang::ast::NewClassExpression &expr) {
1952 auto type =
context.convertType(*expr.type);
1953 auto classTy = dyn_cast<moore::ClassHandleType>(type);
1959 if (!classTy && expr.isSuperClass) {
1960 newObj =
context.getImplicitThisRef();
1961 if (!newObj || !newObj.getType() ||
1962 !isa<moore::ClassHandleType>(newObj.getType())) {
1963 mlir::emitError(loc) <<
"implicit this ref was not set while "
1964 "converting new class function";
1967 auto thisType = cast<moore::ClassHandleType>(newObj.getType());
1969 cast<moore::ClassDeclOp>(*
context.symbolTable.lookupNearestSymbolFrom(
1970 context.intoModuleOp, thisType.getClassSym()));
1971 auto baseClassSym = classDecl.getBase();
1972 classTy = circt::moore::ClassHandleType::get(
context.getContext(),
1973 baseClassSym.value());
1976 newObj = moore::ClassNewOp::create(builder, loc, classTy, {});
1979 const auto *constructor = expr.constructorCall();
1984 if (
const auto *callConstructor =
1985 constructor->as_if<slang::ast::CallExpression>())
1986 if (
const auto *subroutine =
1987 std::get_if<const slang::ast::SubroutineSymbol *>(
1988 &callConstructor->subroutine)) {
1991 if (!(*subroutine)->thisVar) {
1992 mlir::emitError(loc) <<
"Expected subroutine called by new to use an "
1993 "implicit this reference";
1996 if (failed(
context.convertFunction(**subroutine)))
1999 auto savedThis =
context.currentThisRef;
2000 context.currentThisRef = newObj;
2001 llvm::scope_exit restoreThis(
2002 [&] {
context.currentThisRef = savedThis; });
2004 if (!visitCall(*callConstructor, *subroutine))
2013 template <
typename T>
2014 Value visit(T &&node) {
2015 mlir::emitError(loc,
"unsupported expression: ")
2016 << slang::ast::toString(node.kind);
2020 Value visitInvalid(
const slang::ast::Expression &expr) {
2021 mlir::emitError(loc,
"invalid expression");
2032struct LvalueExprVisitor :
public ExprVisitor {
2034 : ExprVisitor(
context, loc, true) {}
2035 using ExprVisitor::visit;
2038 Value visit(
const slang::ast::NamedValueExpression &expr) {
2040 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2044 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2045 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2047 if (
auto *
const property =
2048 expr.symbol.as_if<slang::ast::ClassPropertySymbol>()) {
2052 auto d = mlir::emitError(loc,
"unknown name `") << expr.symbol.name <<
"`";
2053 d.attachNote(
context.convertLocation(expr.symbol.location))
2054 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2059 Value visit(
const slang::ast::HierarchicalValueExpression &expr) {
2061 if (
auto value =
context.valueSymbols.lookup(&expr.symbol))
2065 if (
auto globalOp =
context.globalVariables.lookup(&expr.symbol))
2066 return moore::GetGlobalVariableOp::create(builder, loc, globalOp);
2070 auto d = mlir::emitError(loc,
"unknown hierarchical name `")
2071 << expr.symbol.name <<
"`";
2072 d.attachNote(
context.convertLocation(expr.symbol.location))
2073 <<
"no lvalue generated for " << slang::ast::toString(expr.symbol.kind);
2077 Value visit(
const slang::ast::StreamingConcatenationExpression &expr) {
2078 SmallVector<Value> operands;
2079 for (
auto stream : expr.streams()) {
2080 auto operandLoc =
context.convertLocation(stream.operand->sourceRange);
2081 if (!stream.constantWithWidth.has_value() && stream.withExpr) {
2082 mlir::emitError(operandLoc)
2083 <<
"Moore only support streaming "
2084 "concatenation with fixed size 'with expression'";
2088 if (stream.constantWithWidth.has_value()) {
2089 value =
context.convertLvalueExpression(*stream.withExpr);
2090 auto type = cast<moore::UnpackedType>(
2091 cast<moore::RefType>(value.getType()).getNestedType());
2092 auto intType = moore::RefType::get(moore::IntType::get(
2093 context.getContext(), type.getBitSize().value(), type.getDomain()));
2095 value =
context.materializeConversion(intType, value,
false, loc);
2097 value =
context.convertLvalueExpression(*stream.operand);
2102 operands.push_back(value);
2105 if (operands.size() == 1) {
2108 value = operands.front();
2110 value = moore::ConcatRefOp::create(builder, loc, operands).getResult();
2113 if (expr.getSliceSize() == 0) {
2117 auto type = cast<moore::IntType>(
2118 cast<moore::RefType>(value.getType()).getNestedType());
2119 SmallVector<Value> slicedOperands;
2120 auto widthSum = type.getWidth();
2121 auto domain = type.getDomain();
2122 auto iterMax = widthSum / expr.getSliceSize();
2123 auto remainSize = widthSum % expr.getSliceSize();
2125 for (
size_t i = 0; i < iterMax; i++) {
2126 auto extractResultType = moore::RefType::get(moore::IntType::get(
2127 context.getContext(), expr.getSliceSize(), domain));
2129 auto extracted = moore::ExtractRefOp::create(
2130 builder, loc, extractResultType, value, i * expr.getSliceSize());
2131 slicedOperands.push_back(extracted);
2135 auto extractResultType = moore::RefType::get(
2136 moore::IntType::get(
context.getContext(), remainSize, domain));
2139 moore::ExtractRefOp::create(builder, loc, extractResultType, value,
2140 iterMax * expr.getSliceSize());
2141 slicedOperands.push_back(extracted);
2144 return moore::ConcatRefOp::create(builder, loc, slicedOperands);
2148 template <
typename T>
2149 Value visit(T &&node) {
2150 return context.convertRvalueExpression(node);
2153 Value visitInvalid(
const slang::ast::Expression &expr) {
2154 mlir::emitError(loc,
"invalid expression");
2164Value Context::convertRvalueExpression(
const slang::ast::Expression &expr,
2165 Type requiredType) {
2167 auto value = expr.visit(RvalueExprVisitor(*
this, loc));
2168 if (value && requiredType)
2176 return expr.visit(LvalueExprVisitor(*
this, loc));
2184 if (
auto type = dyn_cast_or_null<moore::IntType>(value.getType()))
2185 if (type.getBitSize() == 1)
2187 if (
auto type = dyn_cast_or_null<moore::UnpackedType>(value.getType()))
2188 return moore::BoolCastOp::create(
builder, value.getLoc(), value);
2189 mlir::emitError(value.getLoc(),
"expression of type ")
2190 << value.getType() <<
" cannot be cast to a boolean";
2196 const slang::ast::Type &astType,
2198 const auto *floatType = astType.as_if<slang::ast::FloatingType>();
2202 if (svreal.isShortReal() &&
2203 floatType->floatKind == slang::ast::FloatingType::ShortReal) {
2204 attr = FloatAttr::get(
builder.getF32Type(), svreal.shortReal().v);
2205 }
else if (svreal.isReal() &&
2206 floatType->floatKind == slang::ast::FloatingType::Real) {
2207 attr = FloatAttr::get(
builder.getF64Type(), svreal.real().v);
2209 mlir::emitError(loc) <<
"invalid real constant";
2213 return moore::ConstantRealOp::create(
builder, loc, attr);
2218 const slang::ast::Type &astType,
2220 slang::ConstantValue intVal = stringLiteral.convertToInt();
2221 auto effectiveWidth = intVal.getEffectiveWidth();
2222 if (!effectiveWidth)
2225 auto intTy = moore::IntType::getInt(
getContext(), effectiveWidth.value());
2227 if (astType.isString()) {
2228 auto immInt = moore::ConstantStringOp::create(
builder, loc, intTy,
2229 stringLiteral.toString())
2231 return moore::IntToStringOp::create(
builder, loc, immInt).getResult();
2238 const slang::ast::Type &astType, Location loc) {
2243 bool typeIsFourValued =
false;
2244 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2248 auto intType = moore::IntType::get(
getContext(), fvint.getBitWidth(),
2249 fvint.hasUnknown() || typeIsFourValued
2252 auto result = moore::ConstantOp::create(
builder, loc, intType, fvint);
2257 const slang::ConstantValue &constant,
2258 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc) {
2266 if (astType.elementType.isIntegral())
2267 bitWidth = astType.elementType.getBitWidth();
2271 bool typeIsFourValued =
false;
2274 if (
auto unpackedType = dyn_cast<moore::UnpackedType>(type))
2285 auto intType = moore::IntType::get(
getContext(), bitWidth, domain);
2287 auto arrType = moore::UnpackedArrayType::get(
2288 getContext(), constant.elements().size(), intType);
2290 llvm::SmallVector<mlir::Value> elemVals;
2291 moore::ConstantOp constOp;
2293 mlir::OpBuilder::InsertionGuard guard(
builder);
2296 for (
auto elem : constant.elements()) {
2298 constOp = moore::ConstantOp::create(
builder, loc, intType, fvInt);
2299 elemVals.push_back(constOp.getResult());
2304 auto arrayOp = moore::ArrayCreateOp::create(
builder, loc, arrType, elemVals);
2306 return arrayOp.getResult();
2310 const slang::ast::Type &type, Location loc) {
2312 if (
auto *arr = type.as_if<slang::ast::FixedSizeUnpackedArrayType>())
2314 if (constant.isInteger())
2316 if (constant.isReal() || constant.isShortReal())
2318 if (constant.isString())
2326 using slang::ast::EvalFlags;
2327 slang::ast::EvalContext evalContext(
2329 slang::ast::LookupLocation::max),
2330 EvalFlags::CacheResults | EvalFlags::SpecparamsAllowed);
2331 return expr.eval(evalContext);
2340 auto type = moore::IntType::get(
getContext(), 1, domain);
2347 if (isa<moore::IntType>(value.getType()))
2354 if (
auto packed = dyn_cast<moore::PackedType>(value.getType()))
2355 if (
auto sbvType = packed.getSimpleBitVector())
2358 mlir::emitError(value.getLoc()) <<
"expression of type " << value.getType()
2359 <<
" cannot be cast to a simple bit vector";
2368 if (isa<moore::IntType>(value.getType()))
2371 auto &builder =
context.builder;
2372 auto packedType = cast<moore::PackedType>(value.getType());
2373 auto intType = packedType.getSimpleBitVector();
2378 if (isa<moore::TimeType>(packedType) &&
2380 value = builder.createOrFold<moore::TimeToLogicOp>(loc, value);
2381 auto scale = moore::ConstantOp::create(builder, loc, intType,
2383 return builder.createOrFold<moore::DivUOp>(loc, value, scale);
2389 if (packedType.containsTimeType()) {
2390 mlir::emitError(loc) <<
"unsupported conversion: " << packedType
2391 <<
" cannot be converted to " << intType
2392 <<
"; contains a time type";
2397 return builder.createOrFold<moore::PackedToSBVOp>(loc, value);
2405 Value value, Location loc) {
2406 if (value.getType() == packedType)
2409 auto &builder =
context.builder;
2410 auto intType = cast<moore::IntType>(value.getType());
2415 if (isa<moore::TimeType>(packedType) &&
2417 auto scale = moore::ConstantOp::create(builder, loc, intType,
2419 value = builder.createOrFold<moore::MulOp>(loc, value, scale);
2420 return builder.createOrFold<moore::LogicToTimeOp>(loc, value);
2427 mlir::emitError(loc) <<
"unsupported conversion: " << intType
2428 <<
" cannot be converted to " << packedType
2429 <<
"; contains a time type";
2434 return builder.createOrFold<moore::SBVToPackedOp>(loc, packedType, value);
2440 moore::ClassHandleType expectedHandleTy) {
2441 auto loc = actualHandle.getLoc();
2443 auto actualTy = actualHandle.getType();
2444 auto actualHandleTy = dyn_cast<moore::ClassHandleType>(actualTy);
2445 if (!actualHandleTy) {
2446 mlir::emitError(loc) <<
"expected a !moore.class<...> value, got "
2452 if (actualHandleTy == expectedHandleTy)
2453 return actualHandle;
2455 if (!
context.isClassDerivedFrom(actualHandleTy, expectedHandleTy)) {
2456 mlir::emitError(loc)
2457 <<
"receiver class " << actualHandleTy.getClassSym()
2458 <<
" is not the same as, or derived from, expected base class "
2459 << expectedHandleTy.getClassSym().getRootReference();
2464 auto casted = moore::ClassUpcastOp::create(
context.builder, loc,
2465 expectedHandleTy, actualHandle)
2473 if (type == value.getType())
2478 auto dstPacked = dyn_cast<moore::PackedType>(type);
2479 auto srcPacked = dyn_cast<moore::PackedType>(value.getType());
2480 auto dstInt = dstPacked ? dstPacked.getSimpleBitVector() : moore::IntType();
2481 auto srcInt = srcPacked ? srcPacked.getSimpleBitVector() : moore::IntType();
2483 if (dstInt && srcInt) {
2491 auto resizedType = moore::IntType::get(
2492 value.getContext(), dstInt.getWidth(), srcPacked.getDomain());
2493 if (dstInt.getWidth() < srcInt.getWidth()) {
2494 value =
builder.createOrFold<moore::TruncOp>(loc, resizedType, value);
2495 }
else if (dstInt.getWidth() > srcInt.getWidth()) {
2497 value =
builder.createOrFold<moore::SExtOp>(loc, resizedType, value);
2499 value =
builder.createOrFold<moore::ZExtOp>(loc, resizedType, value);
2503 if (dstInt.getDomain() != srcInt.getDomain()) {
2505 value =
builder.createOrFold<moore::LogicToIntOp>(loc, value);
2507 value =
builder.createOrFold<moore::IntToLogicOp>(loc, value);
2515 assert(value.getType() == type);
2520 if (isa<moore::StringType>(type) &&
2521 isa<moore::FormatStringType>(value.getType())) {
2522 return builder.createOrFold<moore::FormatStringToStringOp>(loc, value);
2526 if (isa<moore::FormatStringType>(type) &&
2527 isa<moore::StringType>(value.getType())) {
2528 return builder.createOrFold<moore::FormatStringOp>(loc, value);
2532 if (isa<moore::IntType>(type) && isa<moore::RealType>(value.getType())) {
2533 auto twoValInt =
builder.createOrFold<moore::RealToIntOp>(
2534 loc, dyn_cast<moore::IntType>(type).getTwoValued(), value);
2542 if (isa<moore::RealType>(type) && isa<moore::IntType>(value.getType())) {
2545 if (dyn_cast<moore::IntType>(value.getType()).getDomain() ==
2550 dyn_cast<moore::IntType>(value.getType()).getTwoValued(), value,
true,
2554 return builder.createOrFold<moore::SIntToRealOp>(loc, type, twoValInt);
2555 return builder.createOrFold<moore::UIntToRealOp>(loc, type, twoValInt);
2558 auto getBuiltinFloatType = [&](moore::RealType type) -> Type {
2560 return mlir::Float32Type::get(
builder.getContext());
2562 return mlir::Float64Type::get(
builder.getContext());
2566 if (isa<moore::TimeType>(type) && isa<moore::RealType>(value.getType())) {
2568 moore::IntType::get(
builder.getContext(), 64, Domain::TwoValued);
2570 getBuiltinFloatType(cast<moore::RealType>(value.getType()));
2571 auto scale = moore::ConstantRealOp::create(
2572 builder, loc, value.getType(),
2574 auto scaled =
builder.createOrFold<moore::MulRealOp>(loc, value, scale);
2575 auto asInt = moore::RealToIntOp::create(
builder, loc, intType, scaled);
2576 auto asLogic = moore::IntToLogicOp::create(
builder, loc, asInt);
2577 return moore::LogicToTimeOp::create(
builder, loc, asLogic);
2581 if (isa<moore::RealType>(type) && isa<moore::TimeType>(value.getType())) {
2582 auto asLogic = moore::TimeToLogicOp::create(
builder, loc, value);
2583 auto asInt = moore::LogicToIntOp::create(
builder, loc, asLogic);
2584 auto asReal = moore::UIntToRealOp::create(
builder, loc, type, asInt);
2585 Type floatType = getBuiltinFloatType(cast<moore::RealType>(type));
2586 auto scale = moore::ConstantRealOp::create(
2589 return moore::DivRealOp::create(
builder, loc, asReal, scale);
2593 if (isa<moore::StringType>(type)) {
2594 if (
auto intType = dyn_cast<moore::IntType>(value.getType())) {
2596 value = moore::LogicToIntOp::create(
builder, loc, value);
2597 return moore::IntToStringOp::create(
builder, loc, value);
2602 if (
auto intType = dyn_cast<moore::IntType>(type)) {
2603 if (isa<moore::StringType>(value.getType())) {
2604 value = moore::StringToIntOp::create(
builder, loc, intType.getTwoValued(),
2608 return moore::IntToLogicOp::create(
builder, loc, value);
2615 if (isa<moore::FormatStringType>(type)) {
2617 value, isSigned, loc);
2620 return moore::FormatStringOp::create(
builder, loc, asStr, {}, {}, {});
2623 if (isa<moore::RealType>(type) && isa<moore::RealType>(value.getType()))
2624 return builder.createOrFold<moore::ConvertRealOp>(loc, type, value);
2626 if (isa<moore::ClassHandleType>(type) &&
2627 isa<moore::ClassHandleType>(value.getType()))
2631 if (value.getType() != type)
2632 value = moore::ConversionOp::create(
builder, loc, type, value);
2640 auto systemCallRes =
2641 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2644 return moore::UrandomBIOp::create(
builder, loc,
nullptr);
2648 return moore::RandomBIOp::create(
builder, loc,
nullptr);
2652 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2655 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2658 [&]() -> Value {
return moore::TimeBIOp::create(
builder, loc); })
2659 .Default([&]() -> Value {
return {}; });
2660 return systemCallRes();
2665 Location loc, Value value) {
2666 auto systemCallRes =
2667 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2669 .Case(
"$signed", [&]() {
return value; })
2670 .Case(
"$unsigned", [&]() {
return value; })
2674 [&]() -> FailureOr<Value> {
2678 return (Value)moore::Clog2BIOp::create(
builder, loc, value);
2682 return moore::LnBIOp::create(
builder, loc, value);
2686 return moore::Log10BIOp::create(
builder, loc, value);
2690 return moore::SinBIOp::create(
builder, loc, value);
2694 return moore::CosBIOp::create(
builder, loc, value);
2698 return moore::TanBIOp::create(
builder, loc, value);
2702 return moore::ExpBIOp::create(
builder, loc, value);
2706 return moore::SqrtBIOp::create(
builder, loc, value);
2710 return moore::FloorBIOp::create(
builder, loc, value);
2714 return moore::CeilBIOp::create(
builder, loc, value);
2718 return moore::AsinBIOp::create(
builder, loc, value);
2722 return moore::AcosBIOp::create(
builder, loc, value);
2726 return moore::AtanBIOp::create(
builder, loc, value);
2730 return moore::SinhBIOp::create(
builder, loc, value);
2734 return moore::CoshBIOp::create(
builder, loc, value);
2738 return moore::TanhBIOp::create(
builder, loc, value);
2742 return moore::AsinhBIOp::create(
builder, loc, value);
2746 return moore::AcoshBIOp::create(
builder, loc, value);
2750 return moore::AtanhBIOp::create(
builder, loc, value);
2754 return moore::UrandomBIOp::create(
builder, loc, value);
2758 return moore::RandomBIOp::create(
builder, loc, value);
2760 .Case(
"$urandom_range",
2762 return moore::UrandomrangeBIOp::create(
builder, loc, value,
2765 .Case(
"$realtobits",
2767 return moore::RealtobitsBIOp::create(
builder, loc, value);
2769 .Case(
"$bitstoreal",
2771 return moore::BitstorealBIOp::create(
builder, loc, value);
2773 .Case(
"$shortrealtobits",
2775 return moore::ShortrealtobitsBIOp::create(
builder, loc,
2778 .Case(
"$bitstoshortreal",
2780 return moore::BitstoshortrealBIOp::create(
builder, loc,
2785 if (isa<moore::StringType>(value.getType()))
2786 return moore::StringLenOp::create(
builder, loc, value);
2791 return moore::StringToUpperOp::create(
builder, loc, value);
2796 if (isa<moore::RefType>(value.getType()) &&
2797 isa<moore::QueueType>(
2798 cast<moore::RefType>(value.getType()).getNestedType()))
2799 return moore::QueueSizeBIOp::create(
builder, loc, value);
2804 return moore::StringToLowerOp::create(
builder, loc, value);
2809 if (isa<moore::RefType>(value.getType()) &&
2810 isa<moore::QueueType>(
2811 cast<moore::RefType>(value.getType()).getNestedType()))
2812 return moore::QueuePopBackOp::create(
builder, loc, value);
2819 if (isa<moore::RefType>(value.getType()) &&
2820 isa<moore::QueueType>(
2821 cast<moore::RefType>(value.getType()).getNestedType()))
2822 return moore::QueuePopFrontOp::create(
builder, loc, value);
2825 .Default([&]() -> Value {
return {}; });
2826 return systemCallRes();
2831 Location loc, Value value1, Value value2) {
2832 auto systemCallRes =
2833 llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
2836 return moore::StringGetCOp::create(
builder, loc, value1,
2839 .Case(
"$urandom_range",
2841 return moore::UrandomrangeBIOp::create(
builder, loc, value1,
2844 .Default([&]() -> Value {
return {}; });
2845 return systemCallRes();
2850 return context.symbolTable.lookupNearestSymbolFrom(
context.intoModuleOp, sym);
2854 const moore::ClassHandleType &baseTy) {
2855 if (!actualTy || !baseTy)
2858 mlir::SymbolRefAttr actualSym = actualTy.getClassSym();
2859 mlir::SymbolRefAttr baseSym = baseTy.getClassSym();
2861 if (actualSym == baseSym)
2864 auto *op =
resolve(*
this, actualSym);
2865 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2868 mlir::SymbolRefAttr curBase = decl.getBaseAttr();
2871 if (curBase == baseSym)
2873 decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(
resolve(*
this, curBase));
2878moore::ClassHandleType
2880 llvm::StringRef fieldName, Location loc) {
2882 mlir::SymbolRefAttr classSym = actualTy.getClassSym();
2886 auto *op =
resolve(*
this, classSym);
2887 auto decl = llvm::dyn_cast_or_null<moore::ClassDeclOp>(op);
2892 for (
auto &block : decl.getBody()) {
2893 for (
auto &opInBlock : block) {
2895 llvm::dyn_cast<moore::ClassPropertyDeclOp>(&opInBlock)) {
2896 if (prop.getSymName() == fieldName) {
2898 return moore::ClassHandleType::get(actualTy.getContext(), classSym);
2905 classSym = decl.getBaseAttr();
2909 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