10#include "slang/ast/Compilation.h"
11#include "slang/ast/SystemSubroutine.h"
12#include "llvm/ADT/ScopeExit.h"
16using namespace ImportVerilog;
28 bool isTerminated()
const {
return !builder.getInsertionBlock(); }
29 void setTerminated() { builder.clearInsertionPoint(); }
31 Block &createBlock() {
32 assert(builder.getInsertionBlock());
33 auto block = std::make_unique<Block>();
34 block->insertAfter(builder.getInsertionBlock());
35 return *block.release();
38 LogicalResult recursiveForeach(
const slang::ast::ForeachLoopStatement &stmt,
41 const auto &loopDim = stmt.loopDims[level];
42 if (!loopDim.range.has_value())
43 return mlir::emitError(loc) <<
"dynamic loop variable is unsupported";
44 auto &exitBlock = createBlock();
45 auto &stepBlock = createBlock();
46 auto &bodyBlock = createBlock();
47 auto &checkBlock = createBlock();
50 context.loopStack.push_back({&stepBlock, &exitBlock});
51 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
53 const auto &iter = loopDim.loopVar;
54 auto type =
context.convertType(*iter->getDeclaredType());
58 Value initial = moore::ConstantOp::create(
59 builder, loc, cast<moore::IntType>(type), loopDim.range->lower());
62 Value varOp = moore::VariableOp::create(
63 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
64 builder.getStringAttr(iter->name), initial);
65 context.valueSymbols.insertIntoScope(
context.valueSymbols.getCurScope(),
68 cf::BranchOp::create(builder, loc, &checkBlock);
69 builder.setInsertionPointToEnd(&checkBlock);
72 auto upperBound = moore::ConstantOp::create(
73 builder, loc, cast<moore::IntType>(type), loopDim.range->upper());
75 auto var = moore::ReadOp::create(builder, loc, varOp);
76 Value cond = moore::SleOp::create(builder, loc, var, upperBound);
79 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
80 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
81 ty && ty.getDomain() == Domain::FourValued) {
82 cond = moore::LogicToIntOp::create(builder, loc, cond);
84 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
85 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
87 builder.setInsertionPointToEnd(&bodyBlock);
92 for (uint32_t nextLevel = level + 1; nextLevel < stmt.loopDims.size();
94 if (stmt.loopDims[nextLevel].loopVar) {
95 if (failed(recursiveForeach(stmt, nextLevel)))
103 if (failed(
context.convertStatement(stmt.body)))
107 cf::BranchOp::create(builder, loc, &stepBlock);
109 builder.setInsertionPointToEnd(&stepBlock);
112 var = moore::ReadOp::create(builder, loc, varOp);
114 moore::ConstantOp::create(builder, loc, cast<moore::IntType>(type), 1);
115 auto postValue = moore::AddOp::create(builder, loc, var, one).getResult();
116 moore::BlockingAssignOp::create(builder, loc, varOp, postValue);
117 cf::BranchOp::create(builder, loc, &checkBlock);
119 if (exitBlock.hasNoPredecessors()) {
123 builder.setInsertionPointToEnd(&exitBlock);
129 LogicalResult visit(
const slang::ast::EmptyStatement &) {
return success(); }
138 LogicalResult visit(
const slang::ast::StatementList &stmts) {
139 for (
auto *stmt : stmts.list) {
140 if (isTerminated()) {
141 auto loc =
context.convertLocation(stmt->sourceRange);
142 mlir::emitWarning(loc,
"unreachable code");
145 if (failed(
context.convertStatement(*stmt)))
152 LogicalResult visit(
const slang::ast::BlockStatement &stmt) {
153 return context.convertStatement(stmt.body);
157 LogicalResult visit(
const slang::ast::ExpressionStatement &stmt) {
159 if (
const auto *call = stmt.expr.as_if<slang::ast::CallExpression>()) {
160 if (
const auto *info =
161 std::get_if<slang::ast::CallExpression::SystemCallInfo>(
162 &call->subroutine)) {
163 auto handled = visitSystemCall(stmt, *call, *info);
177 if (!call->getSubroutineName().compare(
"$sformat")) {
180 auto *lhsExpr = call->arguments().front();
183 context.convertFormatString(call->arguments().subspan(1), loc,
184 moore::IntFormat::Decimal,
false);
185 if (failed(fmtValue))
188 auto strValue = moore::FormatStringToStringOp::create(builder, loc,
194 if (
auto assignExpr =
195 lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
196 auto lhs =
context.convertLvalueExpression(assignExpr->left());
200 auto convertedValue =
context.materializeConversion(
201 cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
203 moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
211 auto value =
context.convertRvalueExpression(stmt.expr);
217 if (
auto *defOp = value.getDefiningOp())
218 if (isOpTriviallyDead(defOp))
225 LogicalResult visit(
const slang::ast::VariableDeclStatement &stmt) {
226 const auto &var = stmt.symbol;
227 auto type =
context.convertType(*var.getDeclaredType());
232 if (
const auto *init = var.getInitializer()) {
233 initial =
context.convertRvalueExpression(*init, type);
239 auto varOp = moore::VariableOp::create(
240 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
241 builder.getStringAttr(var.name), initial);
242 context.valueSymbols.insertIntoScope(
context.valueSymbols.getCurScope(),
248 LogicalResult visit(
const slang::ast::ConditionalStatement &stmt) {
252 for (
const auto &condition : stmt.conditions) {
253 if (condition.pattern)
254 return mlir::emitError(loc,
255 "match patterns in if conditions not supported");
256 auto cond =
context.convertRvalueExpression(*condition.expr);
259 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
261 allConds = moore::AndOp::create(builder, loc, allConds, cond);
265 assert(allConds &&
"slang guarantees at least one condition");
266 if (
auto ty = dyn_cast<moore::IntType>(allConds.getType());
267 ty && ty.getDomain() == Domain::FourValued) {
268 allConds = moore::LogicToIntOp::create(builder, loc, allConds);
270 allConds = moore::ToBuiltinIntOp::create(builder, loc, allConds);
273 Block &exitBlock = createBlock();
274 Block *falseBlock = stmt.ifFalse ? &createBlock() : nullptr;
275 Block &trueBlock = createBlock();
276 cf::CondBranchOp::create(builder, loc, allConds, &trueBlock,
277 falseBlock ? falseBlock : &exitBlock);
280 builder.setInsertionPointToEnd(&trueBlock);
281 if (failed(
context.convertStatement(stmt.ifTrue)))
284 cf::BranchOp::create(builder, loc, &exitBlock);
288 builder.setInsertionPointToEnd(falseBlock);
289 if (failed(
context.convertStatement(*stmt.ifFalse)))
292 cf::BranchOp::create(builder, loc, &exitBlock);
297 if (exitBlock.hasNoPredecessors()) {
301 builder.setInsertionPointToEnd(&exitBlock);
307 LogicalResult visit(
const slang::ast::CaseStatement &caseStmt) {
308 using slang::ast::AttributeSymbol;
309 using slang::ast::CaseStatementCondition;
310 auto caseExpr =
context.convertRvalueExpression(caseStmt.expr);
317 auto &exitBlock = createBlock();
318 Block *lastMatchBlock =
nullptr;
319 SmallVector<moore::FVIntegerAttr> itemConsts;
321 for (
const auto &item : caseStmt.items) {
324 auto &matchBlock = createBlock();
325 lastMatchBlock = &matchBlock;
330 for (
const auto *expr : item.expressions) {
331 auto value =
context.convertRvalueExpression(*expr);
334 auto itemLoc = value.getLoc();
337 auto maybeConst = value;
338 while (isa_and_nonnull<moore::ConversionOp, moore::IntToLogicOp,
339 moore::LogicToIntOp>(maybeConst.getDefiningOp()))
340 maybeConst = maybeConst.getDefiningOp()->getOperand(0);
341 if (
auto defOp = maybeConst.getDefiningOp<moore::ConstantOp>())
342 itemConsts.push_back(defOp.getValueAttr());
346 switch (caseStmt.condition) {
347 case CaseStatementCondition::Normal:
348 cond = moore::CaseEqOp::create(builder, itemLoc, caseExpr, value);
350 case CaseStatementCondition::WildcardXOrZ:
351 cond = moore::CaseXZEqOp::create(builder, itemLoc, caseExpr, value);
353 case CaseStatementCondition::WildcardJustZ:
354 cond = moore::CaseZEqOp::create(builder, itemLoc, caseExpr, value);
356 case CaseStatementCondition::Inside:
357 mlir::emitError(loc,
"unsupported set membership case statement");
360 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
361 ty && ty.getDomain() == Domain::FourValued) {
362 cond = moore::LogicToIntOp::create(builder, loc, cond);
364 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
368 auto &nextBlock = createBlock();
369 mlir::cf::CondBranchOp::create(builder, itemLoc, cond, &matchBlock,
371 builder.setInsertionPointToEnd(&nextBlock);
377 matchBlock.moveBefore(builder.getInsertionBlock());
380 OpBuilder::InsertionGuard guard(builder);
381 builder.setInsertionPointToEnd(&matchBlock);
382 if (failed(
context.convertStatement(*item.stmt)))
384 if (!isTerminated()) {
385 auto loc =
context.convertLocation(item.stmt->sourceRange);
386 mlir::cf::BranchOp::create(builder, loc, &exitBlock);
390 const auto caseStmtAttrs =
context.compilation.getAttributes(caseStmt);
391 const bool hasFullCaseAttr =
392 llvm::find_if(caseStmtAttrs, [](
const AttributeSymbol *attr) {
393 return attr->name ==
"full_case";
394 }) != caseStmtAttrs.end();
405 auto twoStateExhaustive =
false;
406 if (
auto intType = dyn_cast<moore::IntType>(caseExpr.getType());
407 intType && intType.getWidth() < 32 &&
408 itemConsts.size() == (1 << intType.getWidth())) {
410 llvm::sort(itemConsts, [](
auto a,
auto b) {
411 return a.getValue().getRawValue().ult(b.getValue().getRawValue());
419 for (
auto value : itemConsts) {
420 if (value.getValue() != nextValue)
424 twoStateExhaustive = nextValue.isZero();
435 if ((twoStateExhaustive || (hasFullCaseAttr && !caseStmt.defaultCase)) &&
437 caseStmt.condition == CaseStatementCondition::Normal) {
438 mlir::cf::BranchOp::create(builder, loc, lastMatchBlock);
441 if (caseStmt.defaultCase)
442 if (failed(
context.convertStatement(*caseStmt.defaultCase)))
445 mlir::cf::BranchOp::create(builder, loc, &exitBlock);
450 if (exitBlock.hasNoPredecessors()) {
454 builder.setInsertionPointToEnd(&exitBlock);
460 LogicalResult visit(
const slang::ast::ForLoopStatement &stmt) {
462 for (
auto *initExpr : stmt.initializers)
463 if (!
context.convertRvalueExpression(*initExpr))
467 auto &exitBlock = createBlock();
468 auto &stepBlock = createBlock();
469 auto &bodyBlock = createBlock();
470 auto &checkBlock = createBlock();
471 cf::BranchOp::create(builder, loc, &checkBlock);
474 context.loopStack.push_back({&stepBlock, &exitBlock});
475 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
478 builder.setInsertionPointToEnd(&checkBlock);
479 auto cond =
context.convertRvalueExpression(*stmt.stopExpr);
482 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
483 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
484 ty && ty.getDomain() == Domain::FourValued) {
485 cond = moore::LogicToIntOp::create(builder, loc, cond);
487 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
488 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
491 builder.setInsertionPointToEnd(&bodyBlock);
492 if (failed(
context.convertStatement(stmt.body)))
495 cf::BranchOp::create(builder, loc, &stepBlock);
498 builder.setInsertionPointToEnd(&stepBlock);
499 for (
auto *stepExpr : stmt.steps)
500 if (!
context.convertRvalueExpression(*stepExpr))
503 cf::BranchOp::create(builder, loc, &checkBlock);
507 if (exitBlock.hasNoPredecessors()) {
511 builder.setInsertionPointToEnd(&exitBlock);
516 LogicalResult visit(
const slang::ast::ForeachLoopStatement &stmt) {
517 for (uint32_t level = 0; level < stmt.loopDims.size(); level++) {
518 if (stmt.loopDims[level].loopVar)
519 return recursiveForeach(stmt, level);
525 LogicalResult visit(
const slang::ast::RepeatLoopStatement &stmt) {
526 auto count =
context.convertRvalueExpression(stmt.count);
531 auto &exitBlock = createBlock();
532 auto &stepBlock = createBlock();
533 auto &bodyBlock = createBlock();
534 auto &checkBlock = createBlock();
535 auto currentCount = checkBlock.addArgument(count.getType(), count.getLoc());
536 cf::BranchOp::create(builder, loc, &checkBlock, count);
539 context.loopStack.push_back({&stepBlock, &exitBlock});
540 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
543 builder.setInsertionPointToEnd(&checkBlock);
544 auto cond = builder.createOrFold<moore::BoolCastOp>(loc, currentCount);
545 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
546 ty && ty.getDomain() == Domain::FourValued) {
547 cond = moore::LogicToIntOp::create(builder, loc, cond);
549 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
550 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
553 builder.setInsertionPointToEnd(&bodyBlock);
554 if (failed(
context.convertStatement(stmt.body)))
557 cf::BranchOp::create(builder, loc, &stepBlock);
560 builder.setInsertionPointToEnd(&stepBlock);
561 auto one = moore::ConstantOp::create(
562 builder, count.getLoc(), cast<moore::IntType>(count.getType()), 1);
564 moore::SubOp::create(builder, count.getLoc(), currentCount, one);
565 cf::BranchOp::create(builder, loc, &checkBlock, nextCount);
569 if (exitBlock.hasNoPredecessors()) {
573 builder.setInsertionPointToEnd(&exitBlock);
579 LogicalResult createWhileLoop(
const slang::ast::Expression &condExpr,
580 const slang::ast::Statement &bodyStmt,
583 auto &exitBlock = createBlock();
584 auto &bodyBlock = createBlock();
585 auto &checkBlock = createBlock();
586 cf::BranchOp::create(builder, loc, atLeastOnce ? &bodyBlock : &checkBlock);
588 bodyBlock.moveBefore(&checkBlock);
591 context.loopStack.push_back({&checkBlock, &exitBlock});
592 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
595 builder.setInsertionPointToEnd(&checkBlock);
596 auto cond =
context.convertRvalueExpression(condExpr);
599 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
600 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
601 ty && ty.getDomain() == Domain::FourValued) {
602 cond = moore::LogicToIntOp::create(builder, loc, cond);
604 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
605 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
608 builder.setInsertionPointToEnd(&bodyBlock);
609 if (failed(
context.convertStatement(bodyStmt)))
612 cf::BranchOp::create(builder, loc, &checkBlock);
616 if (exitBlock.hasNoPredecessors()) {
620 builder.setInsertionPointToEnd(&exitBlock);
625 LogicalResult visit(
const slang::ast::WhileLoopStatement &stmt) {
626 return createWhileLoop(stmt.cond, stmt.body,
false);
629 LogicalResult visit(
const slang::ast::DoWhileLoopStatement &stmt) {
630 return createWhileLoop(stmt.cond, stmt.body,
true);
634 LogicalResult visit(
const slang::ast::ForeverLoopStatement &stmt) {
636 auto &exitBlock = createBlock();
637 auto &bodyBlock = createBlock();
638 cf::BranchOp::create(builder, loc, &bodyBlock);
641 context.loopStack.push_back({&bodyBlock, &exitBlock});
642 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
645 builder.setInsertionPointToEnd(&bodyBlock);
646 if (failed(
context.convertStatement(stmt.body)))
649 cf::BranchOp::create(builder, loc, &bodyBlock);
653 if (exitBlock.hasNoPredecessors()) {
657 builder.setInsertionPointToEnd(&exitBlock);
663 LogicalResult visit(
const slang::ast::TimedStatement &stmt) {
664 return context.convertTimingControl(stmt.timing, stmt.stmt);
668 LogicalResult visit(
const slang::ast::ReturnStatement &stmt) {
670 auto expr =
context.convertRvalueExpression(*stmt.expr);
673 mlir::func::ReturnOp::create(builder, loc, expr);
675 mlir::func::ReturnOp::create(builder, loc);
682 LogicalResult visit(
const slang::ast::ContinueStatement &stmt) {
684 return mlir::emitError(loc,
685 "cannot `continue` without a surrounding loop");
686 cf::BranchOp::create(builder, loc,
context.loopStack.back().continueBlock);
692 LogicalResult visit(
const slang::ast::BreakStatement &stmt) {
694 return mlir::emitError(loc,
"cannot `break` without a surrounding loop");
695 cf::BranchOp::create(builder, loc,
context.loopStack.back().breakBlock);
701 LogicalResult visit(
const slang::ast::ImmediateAssertionStatement &stmt) {
702 auto cond =
context.convertRvalueExpression(stmt.cond);
703 cond =
context.convertToBool(cond);
708 if (stmt.ifTrue && stmt.ifTrue->as_if<slang::ast::EmptyStatement>()) {
709 auto defer = moore::DeferAssert::Immediate;
711 defer = moore::DeferAssert::Final;
712 else if (stmt.isDeferred)
713 defer = moore::DeferAssert::Observed;
715 switch (stmt.assertionKind) {
716 case slang::ast::AssertionKind::Assert:
717 moore::AssertOp::create(builder, loc, defer, cond, StringAttr{});
719 case slang::ast::AssertionKind::Assume:
720 moore::AssumeOp::create(builder, loc, defer, cond, StringAttr{});
722 case slang::ast::AssertionKind::CoverProperty:
723 moore::CoverOp::create(builder, loc, defer, cond, StringAttr{});
728 mlir::emitError(loc) <<
"unsupported immediate assertion kind: "
729 << slang::ast::toString(stmt.assertionKind);
734 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
735 ty && ty.getDomain() == Domain::FourValued) {
736 cond = moore::LogicToIntOp::create(builder, loc, cond);
738 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
741 Block &exitBlock = createBlock();
742 Block *falseBlock = stmt.ifFalse ? &createBlock() : nullptr;
743 Block &trueBlock = createBlock();
744 cf::CondBranchOp::create(builder, loc, cond, &trueBlock,
745 falseBlock ? falseBlock : &exitBlock);
748 builder.setInsertionPointToEnd(&trueBlock);
749 if (stmt.ifTrue && failed(
context.convertStatement(*stmt.ifTrue)))
752 cf::BranchOp::create(builder, loc, &exitBlock);
756 builder.setInsertionPointToEnd(falseBlock);
757 if (failed(
context.convertStatement(*stmt.ifFalse)))
760 cf::BranchOp::create(builder, loc, &exitBlock);
765 if (exitBlock.hasNoPredecessors()) {
769 builder.setInsertionPointToEnd(&exitBlock);
775 LogicalResult visit(
const slang::ast::ConcurrentAssertionStatement &stmt) {
776 auto loc =
context.convertLocation(stmt.sourceRange);
786 if (
auto *disableIff =
787 stmt.propertySpec.as_if<slang::ast::DisableIffAssertionExpr>()) {
788 auto disableCond =
context.convertRvalueExpression(disableIff->condition);
789 auto enableCond = moore::NotOp::create(builder, loc, disableCond);
791 enable =
context.convertToI1(enableCond);
792 property =
context.convertAssertionExpression(disableIff->expr, loc);
794 property =
context.convertAssertionExpression(stmt.propertySpec, loc);
801 if (stmt.ifTrue && stmt.ifTrue->as_if<slang::ast::EmptyStatement>()) {
802 switch (stmt.assertionKind) {
803 case slang::ast::AssertionKind::Assert:
804 verif::AssertOp::create(builder, loc, property, enable, StringAttr{});
806 case slang::ast::AssertionKind::Assume:
807 verif::AssumeOp::create(builder, loc, property, enable, StringAttr{});
812 mlir::emitError(loc) <<
"unsupported concurrent assertion kind: "
813 << slang::ast::toString(stmt.assertionKind);
818 <<
"concurrent assertion statements with action blocks "
819 "are not supported yet";
833 getDisplayMessage(std::span<const slang::ast::Expression *const> args) {
834 if (args.size() == 0)
843 if (args[0]->as_if<slang::ast::StringLiteral>()) {
844 return context.convertFormatString(args, loc);
847 if (args.size() == 1) {
848 return context.convertRvalueExpression(
849 *args[0], builder.getType<moore::FormatStringType>());
852 return emitError(loc) <<
"Failed to convert Display Message!";
859 visitSystemCall(
const slang::ast::ExpressionStatement &stmt,
860 const slang::ast::CallExpression &expr,
861 const slang::ast::CallExpression::SystemCallInfo &info) {
862 const auto &subroutine = *
info.subroutine;
863 auto args = expr.arguments();
867 if (subroutine.name ==
"$stop") {
868 createFinishMessage(args.size() >= 1 ? args[0] : nullptr);
869 moore::StopBIOp::create(builder, loc);
873 if (subroutine.name ==
"$finish") {
874 createFinishMessage(args.size() >= 1 ? args[0] : nullptr);
875 moore::FinishBIOp::create(builder, loc, 0);
876 moore::UnreachableOp::create(builder, loc);
881 if (subroutine.name ==
"$exit") {
891 bool isDisplay =
false;
892 bool appendNewline =
false;
893 StringRef remainingName = subroutine.name;
894 if (remainingName.consume_front(
"$display")) {
896 appendNewline =
true;
897 }
else if (remainingName.consume_front(
"$write")) {
902 using moore::IntFormat;
903 IntFormat defaultFormat = IntFormat::Decimal;
904 if (isDisplay && !remainingName.empty()) {
905 if (remainingName ==
"b")
906 defaultFormat = IntFormat::Binary;
907 else if (remainingName ==
"o")
908 defaultFormat = IntFormat::Octal;
909 else if (remainingName ==
"h")
910 defaultFormat = IntFormat::HexLower;
917 context.convertFormatString(args, loc, defaultFormat, appendNewline);
920 if (*message == Value{})
922 moore::DisplayBIOp::create(builder, loc, *message);
927 using moore::Severity;
928 std::optional<Severity> severity;
929 if (subroutine.name ==
"$info")
930 severity = Severity::Info;
931 else if (subroutine.name ==
"$warning")
932 severity = Severity::Warning;
933 else if (subroutine.name ==
"$error")
934 severity = Severity::Error;
935 else if (subroutine.name ==
"$fatal")
936 severity = Severity::Fatal;
940 const slang::ast::Expression *verbosityExpr =
nullptr;
941 if (severity == Severity::Fatal && args.size() >= 1) {
942 verbosityExpr = args[0];
943 args = args.subspan(1);
946 FailureOr<Value> maybeMessage = getDisplayMessage(args);
947 if (failed(maybeMessage))
949 auto message = maybeMessage.value();
951 if (message == Value{})
952 message = moore::FormatLiteralOp::create(builder, loc,
"");
953 moore::SeverityBIOp::create(builder, loc, *severity, message);
956 if (severity == Severity::Fatal) {
957 createFinishMessage(verbosityExpr);
958 moore::FinishBIOp::create(builder, loc, 1);
959 moore::UnreachableOp::create(builder, loc);
967 if (args.size() >= 1 && args[0]->type->isQueue()) {
968 auto queue =
context.convertLvalueExpression(*args[0]);
972 if (subroutine.name ==
"delete") {
973 if (args.size() == 1) {
974 moore::QueueClearOp::create(builder, loc, queue);
977 if (args.size() == 2) {
978 auto index =
context.convertRvalueExpression(*args[1]);
979 moore::QueueDeleteOp::create(builder, loc, queue, index);
982 }
else if (subroutine.name ==
"insert" && args.size() == 3) {
983 auto index =
context.convertRvalueExpression(*args[1]);
984 auto item =
context.convertRvalueExpression(*args[2]);
986 moore::QueueInsertOp::create(builder, loc, queue, index, item);
988 }
else if (subroutine.name ==
"push_back" && args.size() == 2) {
989 auto item =
context.convertRvalueExpression(*args[1]);
990 moore::QueuePushBackOp::create(builder, loc, queue, item);
992 }
else if (subroutine.name ==
"push_front" && args.size() == 2) {
993 auto item =
context.convertRvalueExpression(*args[1]);
994 moore::QueuePushFrontOp::create(builder, loc, queue, item);
1007 void createFinishMessage(
const slang::ast::Expression *verbosityExpr) {
1008 unsigned verbosity = 1;
1009 if (verbosityExpr) {
1011 context.evaluateConstant(*verbosityExpr).integer().as<
unsigned>();
1012 assert(value &&
"Slang guarantees constant verbosity parameter");
1017 moore::FinishMessageBIOp::create(builder, loc, verbosity > 1);
1021 LogicalResult visit(
const slang::ast::EventTriggerStatement &stmt) {
1023 mlir::emitError(loc) <<
"unsupported delayed event trigger";
1029 auto target =
context.convertLvalueExpression(stmt.target);
1035 Value inverted = moore::ReadOp::create(builder, loc, target);
1036 inverted = moore::NotOp::create(builder, loc, inverted);
1038 if (stmt.isNonBlocking)
1039 moore::NonBlockingAssignOp::create(builder, loc, target, inverted);
1041 moore::BlockingAssignOp::create(builder, loc, target, inverted);
1046 template <
typename T>
1047 LogicalResult visit(T &&stmt) {
1048 mlir::emitError(loc,
"unsupported statement: ")
1049 << slang::ast::toString(stmt.kind);
1050 return mlir::failure();
1053 LogicalResult visitInvalid(
const slang::ast::Statement &stmt) {
1054 mlir::emitError(loc,
"invalid statement: ")
1055 << slang::ast::toString(stmt.kind);
1056 return mlir::failure();
1061LogicalResult Context::convertStatement(
const slang::ast::Statement &stmt) {
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static FVInt getZero(unsigned numBits)
Construct an FVInt with all bits set to 0.
This helps visit TypeOp nodes.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
OpBuilder builder
The builder used to create IR operations.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.