11#include "mlir/Dialect/Func/IR/FuncOps.h"
12#include "mlir/IR/Builders.h"
13#include "mlir/IR/Diagnostics.h"
14#include "slang/ast/Compilation.h"
15#include "slang/ast/SemanticFacts.h"
16#include "slang/ast/Statement.h"
17#include "slang/ast/SystemSubroutine.h"
18#include "llvm/ADT/ScopeExit.h"
22using namespace ImportVerilog;
34 bool isTerminated()
const {
return !builder.getInsertionBlock(); }
35 void setTerminated() { builder.clearInsertionPoint(); }
37 Block &createBlock() {
38 assert(builder.getInsertionBlock());
39 auto block = std::make_unique<Block>();
40 block->insertAfter(builder.getInsertionBlock());
41 return *block.release();
44 LogicalResult recursiveForeach(
const slang::ast::ForeachLoopStatement &stmt,
47 const auto &loopDim = stmt.loopDims[level];
48 if (!loopDim.range.has_value())
49 return mlir::emitError(loc) <<
"dynamic loop variable is unsupported";
50 auto &exitBlock = createBlock();
51 auto &stepBlock = createBlock();
52 auto &bodyBlock = createBlock();
53 auto &checkBlock = createBlock();
56 context.loopStack.push_back({&stepBlock, &exitBlock});
57 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
59 const auto &iter = loopDim.loopVar;
60 auto type =
context.convertType(*iter->getDeclaredType());
64 Value initial = moore::ConstantOp::create(
65 builder, loc, cast<moore::IntType>(type), loopDim.range->lower());
68 Value varOp = moore::VariableOp::create(
69 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
70 builder.getStringAttr(iter->name), initial);
71 context.valueSymbols.insertIntoScope(
context.valueSymbols.getCurScope(),
74 cf::BranchOp::create(builder, loc, &checkBlock);
75 builder.setInsertionPointToEnd(&checkBlock);
78 auto upperBound = moore::ConstantOp::create(
79 builder, loc, cast<moore::IntType>(type), loopDim.range->upper());
81 auto var = moore::ReadOp::create(builder, loc, varOp);
82 Value cond = moore::SleOp::create(builder, loc, var, upperBound);
85 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
86 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
87 ty && ty.getDomain() == Domain::FourValued) {
88 cond = moore::LogicToIntOp::create(builder, loc, cond);
90 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
91 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
93 builder.setInsertionPointToEnd(&bodyBlock);
98 for (uint32_t nextLevel = level + 1; nextLevel < stmt.loopDims.size();
100 if (stmt.loopDims[nextLevel].loopVar) {
101 if (failed(recursiveForeach(stmt, nextLevel)))
109 if (failed(
context.convertStatement(stmt.body)))
113 cf::BranchOp::create(builder, loc, &stepBlock);
115 builder.setInsertionPointToEnd(&stepBlock);
118 var = moore::ReadOp::create(builder, loc, varOp);
120 moore::ConstantOp::create(builder, loc, cast<moore::IntType>(type), 1);
121 auto postValue = moore::AddOp::create(builder, loc, var, one).getResult();
122 moore::BlockingAssignOp::create(builder, loc, varOp, postValue);
123 cf::BranchOp::create(builder, loc, &checkBlock);
125 if (exitBlock.hasNoPredecessors()) {
129 builder.setInsertionPointToEnd(&exitBlock);
135 LogicalResult visit(
const slang::ast::EmptyStatement &) {
return success(); }
144 LogicalResult visit(
const slang::ast::StatementList &stmts) {
145 for (
auto *stmt : stmts.list) {
146 if (isTerminated()) {
147 auto loc =
context.convertLocation(stmt->sourceRange);
148 mlir::emitWarning(loc,
"unreachable code");
151 if (failed(
context.convertStatement(*stmt)))
161 LogicalResult visit(
const slang::ast::BlockStatement &stmt) {
162 moore::JoinKind kind;
163 switch (stmt.blockKind) {
164 case slang::ast::StatementBlockKind::Sequential:
166 return context.convertStatement(stmt.body);
167 case slang::ast::StatementBlockKind::JoinAll:
168 kind = moore::JoinKind::Join;
170 case slang::ast::StatementBlockKind::JoinAny:
171 kind = moore::JoinKind::JoinAny;
173 case slang::ast::StatementBlockKind::JoinNone:
174 kind = moore::JoinKind::JoinNone;
181 auto &threadList = stmt.body.as<slang::ast::StatementList>();
182 unsigned int threadCount = threadList.list.size();
184 auto forkOp = moore::ForkJoinOp::create(builder, loc, kind, threadCount);
185 OpBuilder::InsertionGuard guard(builder);
188 for (
auto *thread : threadList.list) {
189 auto &tBlock = forkOp->getRegion(i).emplaceBlock();
190 builder.setInsertionPointToStart(&tBlock);
193 if (failed(
context.convertStatement(*thread)))
195 moore::CompleteOp::create(builder, loc);
202 LogicalResult visit(
const slang::ast::ExpressionStatement &stmt) {
204 if (
const auto *call = stmt.expr.as_if<slang::ast::CallExpression>()) {
205 if (
const auto *info =
206 std::get_if<slang::ast::CallExpression::SystemCallInfo>(
207 &call->subroutine)) {
208 auto handled = visitSystemCall(stmt, *call, *info);
222 if (!call->getSubroutineName().compare(
"$sformat") ||
223 !call->getSubroutineName().compare(
"$swrite")) {
226 auto *lhsExpr = call->arguments().front();
229 context.convertFormatString(call->arguments().subspan(1), loc,
230 moore::IntFormat::Decimal,
false);
231 if (failed(fmtValue))
234 auto strValue = moore::FormatStringToStringOp::create(builder, loc,
240 if (
auto assignExpr =
241 lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
242 auto lhs =
context.convertLvalueExpression(assignExpr->left());
246 auto convertedValue =
context.materializeConversion(
247 cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
249 moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
257 auto value =
context.convertRvalueExpression(stmt.expr);
263 if (
auto *defOp = value.getDefiningOp())
264 if (isOpTriviallyDead(defOp))
271 LogicalResult visit(
const slang::ast::VariableDeclStatement &stmt) {
272 const auto &var = stmt.symbol;
273 auto type =
context.convertType(*var.getDeclaredType());
278 if (
const auto *init = var.getInitializer()) {
279 initial =
context.convertRvalueExpression(*init, type);
285 auto varOp = moore::VariableOp::create(
286 builder, loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
287 builder.getStringAttr(var.name), initial);
288 context.valueSymbols.insertIntoScope(
context.valueSymbols.getCurScope(),
294 LogicalResult visit(
const slang::ast::ConditionalStatement &stmt) {
298 for (
const auto &condition : stmt.conditions) {
299 if (condition.pattern)
300 return mlir::emitError(loc,
301 "match patterns in if conditions not supported");
302 auto cond =
context.convertRvalueExpression(*condition.expr);
305 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
307 allConds = moore::AndOp::create(builder, loc, allConds, cond);
311 assert(allConds &&
"slang guarantees at least one condition");
312 if (
auto ty = dyn_cast<moore::IntType>(allConds.getType());
313 ty && ty.getDomain() == Domain::FourValued) {
314 allConds = moore::LogicToIntOp::create(builder, loc, allConds);
316 allConds = moore::ToBuiltinIntOp::create(builder, loc, allConds);
319 Block &exitBlock = createBlock();
320 Block *falseBlock = stmt.ifFalse ? &createBlock() : nullptr;
321 Block &trueBlock = createBlock();
322 cf::CondBranchOp::create(builder, loc, allConds, &trueBlock,
323 falseBlock ? falseBlock : &exitBlock);
326 builder.setInsertionPointToEnd(&trueBlock);
327 if (failed(
context.convertStatement(stmt.ifTrue)))
330 cf::BranchOp::create(builder, loc, &exitBlock);
334 builder.setInsertionPointToEnd(falseBlock);
335 if (failed(
context.convertStatement(*stmt.ifFalse)))
338 cf::BranchOp::create(builder, loc, &exitBlock);
343 if (exitBlock.hasNoPredecessors()) {
347 builder.setInsertionPointToEnd(&exitBlock);
353 LogicalResult visit(
const slang::ast::CaseStatement &caseStmt) {
354 using slang::ast::AttributeSymbol;
355 using slang::ast::CaseStatementCondition;
356 auto caseExpr =
context.convertRvalueExpression(caseStmt.expr);
363 auto &exitBlock = createBlock();
364 Block *lastMatchBlock =
nullptr;
365 SmallVector<moore::FVIntegerAttr> itemConsts;
367 for (
const auto &item : caseStmt.items) {
370 auto &matchBlock = createBlock();
371 lastMatchBlock = &matchBlock;
376 for (
const auto *expr : item.expressions) {
377 auto value =
context.convertRvalueExpression(*expr);
380 auto itemLoc = value.getLoc();
383 auto maybeConst = value;
384 while (isa_and_nonnull<moore::ConversionOp, moore::IntToLogicOp,
385 moore::LogicToIntOp>(maybeConst.getDefiningOp()))
386 maybeConst = maybeConst.getDefiningOp()->getOperand(0);
387 if (
auto defOp = maybeConst.getDefiningOp<moore::ConstantOp>())
388 itemConsts.push_back(defOp.getValueAttr());
392 switch (caseStmt.condition) {
393 case CaseStatementCondition::Normal:
394 cond = moore::CaseEqOp::create(builder, itemLoc, caseExpr, value);
396 case CaseStatementCondition::WildcardXOrZ:
397 cond = moore::CaseXZEqOp::create(builder, itemLoc, caseExpr, value);
399 case CaseStatementCondition::WildcardJustZ:
400 cond = moore::CaseZEqOp::create(builder, itemLoc, caseExpr, value);
402 case CaseStatementCondition::Inside:
403 mlir::emitError(loc,
"unsupported set membership case statement");
406 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
407 ty && ty.getDomain() == Domain::FourValued) {
408 cond = moore::LogicToIntOp::create(builder, loc, cond);
410 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
414 auto &nextBlock = createBlock();
415 mlir::cf::CondBranchOp::create(builder, itemLoc, cond, &matchBlock,
417 builder.setInsertionPointToEnd(&nextBlock);
423 matchBlock.moveBefore(builder.getInsertionBlock());
426 OpBuilder::InsertionGuard guard(builder);
427 builder.setInsertionPointToEnd(&matchBlock);
428 if (failed(
context.convertStatement(*item.stmt)))
430 if (!isTerminated()) {
431 auto loc =
context.convertLocation(item.stmt->sourceRange);
432 mlir::cf::BranchOp::create(builder, loc, &exitBlock);
436 const auto caseStmtAttrs =
context.compilation.getAttributes(caseStmt);
437 const bool hasFullCaseAttr =
438 llvm::find_if(caseStmtAttrs, [](
const AttributeSymbol *attr) {
439 return attr->name ==
"full_case";
440 }) != caseStmtAttrs.end();
451 auto twoStateExhaustive =
false;
452 if (
auto intType = dyn_cast<moore::IntType>(caseExpr.getType());
453 intType && intType.getWidth() < 32 &&
454 itemConsts.size() == (1 << intType.getWidth())) {
456 llvm::sort(itemConsts, [](
auto a,
auto b) {
457 return a.getValue().getRawValue().ult(
b.getValue().getRawValue());
465 for (
auto value : itemConsts) {
466 if (value.getValue() != nextValue)
470 twoStateExhaustive = nextValue.isZero();
481 if ((twoStateExhaustive || (hasFullCaseAttr && !caseStmt.defaultCase)) &&
483 caseStmt.condition == CaseStatementCondition::Normal) {
484 mlir::cf::BranchOp::create(builder, loc, lastMatchBlock);
487 if (caseStmt.defaultCase)
488 if (failed(
context.convertStatement(*caseStmt.defaultCase)))
491 mlir::cf::BranchOp::create(builder, loc, &exitBlock);
496 if (exitBlock.hasNoPredecessors()) {
500 builder.setInsertionPointToEnd(&exitBlock);
506 LogicalResult visit(
const slang::ast::ForLoopStatement &stmt) {
508 for (
auto *initExpr : stmt.initializers)
509 if (!
context.convertRvalueExpression(*initExpr))
513 auto &exitBlock = createBlock();
514 auto &stepBlock = createBlock();
515 auto &bodyBlock = createBlock();
516 auto &checkBlock = createBlock();
517 cf::BranchOp::create(builder, loc, &checkBlock);
520 context.loopStack.push_back({&stepBlock, &exitBlock});
521 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
524 builder.setInsertionPointToEnd(&checkBlock);
525 auto cond =
context.convertRvalueExpression(*stmt.stopExpr);
528 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
529 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
530 ty && ty.getDomain() == Domain::FourValued) {
531 cond = moore::LogicToIntOp::create(builder, loc, cond);
533 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
534 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
537 builder.setInsertionPointToEnd(&bodyBlock);
538 if (failed(
context.convertStatement(stmt.body)))
541 cf::BranchOp::create(builder, loc, &stepBlock);
544 builder.setInsertionPointToEnd(&stepBlock);
545 for (
auto *stepExpr : stmt.steps)
546 if (!
context.convertRvalueExpression(*stepExpr))
549 cf::BranchOp::create(builder, loc, &checkBlock);
553 if (exitBlock.hasNoPredecessors()) {
557 builder.setInsertionPointToEnd(&exitBlock);
562 LogicalResult visit(
const slang::ast::ForeachLoopStatement &stmt) {
563 for (uint32_t level = 0; level < stmt.loopDims.size(); level++) {
564 if (stmt.loopDims[level].loopVar)
565 return recursiveForeach(stmt, level);
571 LogicalResult visit(
const slang::ast::RepeatLoopStatement &stmt) {
572 auto count =
context.convertRvalueExpression(stmt.count);
577 auto &exitBlock = createBlock();
578 auto &stepBlock = createBlock();
579 auto &bodyBlock = createBlock();
580 auto &checkBlock = createBlock();
581 auto currentCount = checkBlock.addArgument(count.getType(), count.getLoc());
582 cf::BranchOp::create(builder, loc, &checkBlock, count);
585 context.loopStack.push_back({&stepBlock, &exitBlock});
586 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
589 builder.setInsertionPointToEnd(&checkBlock);
590 auto cond = builder.createOrFold<moore::BoolCastOp>(loc, currentCount);
591 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
592 ty && ty.getDomain() == Domain::FourValued) {
593 cond = moore::LogicToIntOp::create(builder, loc, cond);
595 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
596 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
599 builder.setInsertionPointToEnd(&bodyBlock);
600 if (failed(
context.convertStatement(stmt.body)))
603 cf::BranchOp::create(builder, loc, &stepBlock);
606 builder.setInsertionPointToEnd(&stepBlock);
607 auto one = moore::ConstantOp::create(
608 builder, count.getLoc(), cast<moore::IntType>(count.getType()), 1);
610 moore::SubOp::create(builder, count.getLoc(), currentCount, one);
611 cf::BranchOp::create(builder, loc, &checkBlock, nextCount);
615 if (exitBlock.hasNoPredecessors()) {
619 builder.setInsertionPointToEnd(&exitBlock);
625 LogicalResult createWhileLoop(
const slang::ast::Expression &condExpr,
626 const slang::ast::Statement &bodyStmt,
629 auto &exitBlock = createBlock();
630 auto &bodyBlock = createBlock();
631 auto &checkBlock = createBlock();
632 cf::BranchOp::create(builder, loc, atLeastOnce ? &bodyBlock : &checkBlock);
634 bodyBlock.moveBefore(&checkBlock);
637 context.loopStack.push_back({&checkBlock, &exitBlock});
638 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
641 builder.setInsertionPointToEnd(&checkBlock);
642 auto cond =
context.convertRvalueExpression(condExpr);
645 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
646 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
647 ty && ty.getDomain() == Domain::FourValued) {
648 cond = moore::LogicToIntOp::create(builder, loc, cond);
650 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
651 cf::CondBranchOp::create(builder, loc, cond, &bodyBlock, &exitBlock);
654 builder.setInsertionPointToEnd(&bodyBlock);
655 if (failed(
context.convertStatement(bodyStmt)))
658 cf::BranchOp::create(builder, loc, &checkBlock);
662 if (exitBlock.hasNoPredecessors()) {
666 builder.setInsertionPointToEnd(&exitBlock);
671 LogicalResult visit(
const slang::ast::WhileLoopStatement &stmt) {
672 return createWhileLoop(stmt.cond, stmt.body,
false);
675 LogicalResult visit(
const slang::ast::DoWhileLoopStatement &stmt) {
676 return createWhileLoop(stmt.cond, stmt.body,
true);
680 LogicalResult visit(
const slang::ast::ForeverLoopStatement &stmt) {
682 auto &exitBlock = createBlock();
683 auto &bodyBlock = createBlock();
684 cf::BranchOp::create(builder, loc, &bodyBlock);
687 context.loopStack.push_back({&bodyBlock, &exitBlock});
688 llvm::scope_exit done([&] {
context.loopStack.pop_back(); });
691 builder.setInsertionPointToEnd(&bodyBlock);
692 if (failed(
context.convertStatement(stmt.body)))
695 cf::BranchOp::create(builder, loc, &bodyBlock);
699 if (exitBlock.hasNoPredecessors()) {
703 builder.setInsertionPointToEnd(&exitBlock);
709 LogicalResult visit(
const slang::ast::TimedStatement &stmt) {
710 return context.convertTimingControl(stmt.timing, stmt.stmt);
714 LogicalResult visit(
const slang::ast::ReturnStatement &stmt) {
716 auto expr =
context.convertRvalueExpression(*stmt.expr);
719 mlir::func::ReturnOp::create(builder, loc, expr);
721 mlir::func::ReturnOp::create(builder, loc);
728 LogicalResult visit(
const slang::ast::ContinueStatement &stmt) {
730 return mlir::emitError(loc,
731 "cannot `continue` without a surrounding loop");
732 cf::BranchOp::create(builder, loc,
context.loopStack.back().continueBlock);
738 LogicalResult visit(
const slang::ast::BreakStatement &stmt) {
740 return mlir::emitError(loc,
"cannot `break` without a surrounding loop");
741 cf::BranchOp::create(builder, loc,
context.loopStack.back().breakBlock);
747 LogicalResult visit(
const slang::ast::ImmediateAssertionStatement &stmt) {
748 auto cond =
context.convertRvalueExpression(stmt.cond);
749 cond =
context.convertToBool(cond);
754 if (stmt.ifTrue && stmt.ifTrue->as_if<slang::ast::EmptyStatement>()) {
755 auto defer = moore::DeferAssert::Immediate;
757 defer = moore::DeferAssert::Final;
758 else if (stmt.isDeferred)
759 defer = moore::DeferAssert::Observed;
761 switch (stmt.assertionKind) {
762 case slang::ast::AssertionKind::Assert:
763 moore::AssertOp::create(builder, loc, defer, cond, StringAttr{});
765 case slang::ast::AssertionKind::Assume:
766 moore::AssumeOp::create(builder, loc, defer, cond, StringAttr{});
768 case slang::ast::AssertionKind::CoverProperty:
769 moore::CoverOp::create(builder, loc, defer, cond, StringAttr{});
774 mlir::emitError(loc) <<
"unsupported immediate assertion kind: "
775 << slang::ast::toString(stmt.assertionKind);
780 if (
auto ty = dyn_cast<moore::IntType>(cond.getType());
781 ty && ty.getDomain() == Domain::FourValued) {
782 cond = moore::LogicToIntOp::create(builder, loc, cond);
784 cond = moore::ToBuiltinIntOp::create(builder, loc, cond);
787 Block &exitBlock = createBlock();
788 Block *falseBlock = stmt.ifFalse ? &createBlock() : nullptr;
789 Block &trueBlock = createBlock();
790 cf::CondBranchOp::create(builder, loc, cond, &trueBlock,
791 falseBlock ? falseBlock : &exitBlock);
794 builder.setInsertionPointToEnd(&trueBlock);
795 if (stmt.ifTrue && failed(
context.convertStatement(*stmt.ifTrue)))
798 cf::BranchOp::create(builder, loc, &exitBlock);
802 builder.setInsertionPointToEnd(falseBlock);
803 if (failed(
context.convertStatement(*stmt.ifFalse)))
806 cf::BranchOp::create(builder, loc, &exitBlock);
811 if (exitBlock.hasNoPredecessors()) {
815 builder.setInsertionPointToEnd(&exitBlock);
821 LogicalResult visit(
const slang::ast::ConcurrentAssertionStatement &stmt) {
822 auto loc =
context.convertLocation(stmt.sourceRange);
833 const slang::ast::AssertionExpr *propertySpec;
834 const slang::ast::ClockingAssertionExpr *clocking =
835 stmt.propertySpec.as_if<slang::ast::ClockingAssertionExpr>();
837 propertySpec = &(clocking->expr);
839 propertySpec = &(stmt.propertySpec);
841 if (
auto *disableIff =
842 propertySpec->as_if<slang::ast::DisableIffAssertionExpr>()) {
845 auto disableCond =
context.convertRvalueExpression(disableIff->condition);
846 auto enableCond = moore::NotOp::create(builder, loc, disableCond);
848 enable =
context.convertToI1(enableCond);
852 auto clockingExpr = slang::ast::ClockingAssertionExpr(
853 clocking->clocking, disableIff->expr);
854 property =
context.convertAssertionExpression(clockingExpr, loc);
856 property =
context.convertAssertionExpression(disableIff->expr, loc);
859 property =
context.convertAssertionExpression(stmt.propertySpec, loc);
866 if (stmt.ifTrue && stmt.ifTrue->as_if<slang::ast::EmptyStatement>()) {
867 switch (stmt.assertionKind) {
868 case slang::ast::AssertionKind::Assert:
869 verif::AssertOp::create(builder, loc, property, enable, StringAttr{});
871 case slang::ast::AssertionKind::Assume:
872 verif::AssumeOp::create(builder, loc, property, enable, StringAttr{});
877 mlir::emitError(loc) <<
"unsupported concurrent assertion kind: "
878 << slang::ast::toString(stmt.assertionKind);
883 <<
"concurrent assertion statements with action blocks "
884 "are not supported yet";
898 getDisplayMessage(std::span<const slang::ast::Expression *const> args) {
899 if (args.size() == 0)
908 if (args[0]->as_if<slang::ast::StringLiteral>()) {
909 return context.convertFormatString(args, loc);
912 if (args.size() == 1) {
913 return context.convertRvalueExpression(
914 *args[0], builder.getType<moore::FormatStringType>());
917 return emitError(loc) <<
"Failed to convert Display Message!";
924 visitSystemCall(
const slang::ast::ExpressionStatement &stmt,
925 const slang::ast::CallExpression &expr,
926 const slang::ast::CallExpression::SystemCallInfo &info) {
927 const auto &subroutine = *
info.subroutine;
928 auto args = expr.arguments();
932 if (subroutine.name ==
"$stop") {
933 createFinishMessage(args.size() >= 1 ? args[0] : nullptr);
934 moore::StopBIOp::create(builder, loc);
938 if (subroutine.name ==
"$finish") {
939 createFinishMessage(args.size() >= 1 ? args[0] : nullptr);
940 moore::FinishBIOp::create(builder, loc, 0);
941 moore::UnreachableOp::create(builder, loc);
946 if (subroutine.name ==
"$exit") {
956 bool isDisplay =
false;
957 bool appendNewline =
false;
958 StringRef remainingName = subroutine.name;
959 if (remainingName.consume_front(
"$display")) {
961 appendNewline =
true;
962 }
else if (remainingName.consume_front(
"$write")) {
967 using moore::IntFormat;
968 IntFormat defaultFormat = IntFormat::Decimal;
969 if (isDisplay && !remainingName.empty()) {
970 if (remainingName ==
"b")
971 defaultFormat = IntFormat::Binary;
972 else if (remainingName ==
"o")
973 defaultFormat = IntFormat::Octal;
974 else if (remainingName ==
"h")
975 defaultFormat = IntFormat::HexLower;
982 context.convertFormatString(args, loc, defaultFormat, appendNewline);
985 if (*message == Value{})
987 moore::DisplayBIOp::create(builder, loc, *message);
992 using moore::Severity;
993 std::optional<Severity> severity;
994 if (subroutine.name ==
"$info")
995 severity = Severity::Info;
996 else if (subroutine.name ==
"$warning")
997 severity = Severity::Warning;
998 else if (subroutine.name ==
"$error")
999 severity = Severity::Error;
1000 else if (subroutine.name ==
"$fatal")
1001 severity = Severity::Fatal;
1005 const slang::ast::Expression *verbosityExpr =
nullptr;
1006 if (severity == Severity::Fatal && args.size() >= 1) {
1007 verbosityExpr = args[0];
1008 args = args.subspan(1);
1011 FailureOr<Value> maybeMessage = getDisplayMessage(args);
1012 if (failed(maybeMessage))
1014 auto message = maybeMessage.value();
1016 if (message == Value{})
1017 message = moore::FormatLiteralOp::create(builder, loc,
"");
1018 moore::SeverityBIOp::create(builder, loc, *severity, message);
1021 if (severity == Severity::Fatal) {
1022 createFinishMessage(verbosityExpr);
1023 moore::FinishBIOp::create(builder, loc, 1);
1024 moore::UnreachableOp::create(builder, loc);
1032 if (args.size() >= 1 && args[0]->type->isQueue()) {
1033 auto queue =
context.convertLvalueExpression(*args[0]);
1037 if (subroutine.name ==
"delete") {
1038 if (args.size() == 1) {
1039 moore::QueueClearOp::create(builder, loc, queue);
1042 if (args.size() == 2) {
1043 auto index =
context.convertRvalueExpression(*args[1]);
1044 moore::QueueDeleteOp::create(builder, loc, queue, index);
1047 }
else if (subroutine.name ==
"insert" && args.size() == 3) {
1048 auto index =
context.convertRvalueExpression(*args[1]);
1049 auto item =
context.convertRvalueExpression(*args[2]);
1051 moore::QueueInsertOp::create(builder, loc, queue, index, item);
1053 }
else if (subroutine.name ==
"push_back" && args.size() == 2) {
1054 auto item =
context.convertRvalueExpression(*args[1]);
1055 moore::QueuePushBackOp::create(builder, loc, queue, item);
1057 }
else if (subroutine.name ==
"push_front" && args.size() == 2) {
1058 auto item =
context.convertRvalueExpression(*args[1]);
1059 moore::QueuePushFrontOp::create(builder, loc, queue, item);
1067 if (args.size() >= 1 && args[0]->type->isAssociativeArray()) {
1068 auto assocArray =
context.convertLvalueExpression(*args[0]);
1073 if (subroutine.name ==
"delete") {
1074 if (args.size() == 1) {
1075 moore::AssocArrayClearOp::create(builder, loc, assocArray);
1078 if (args.size() == 2) {
1079 auto index =
context.convertRvalueExpression(*args[1]);
1080 moore::AssocArrayDeleteOp::create(builder, loc, assocArray, index);
1092 void createFinishMessage(
const slang::ast::Expression *verbosityExpr) {
1093 unsigned verbosity = 1;
1094 if (verbosityExpr) {
1096 context.evaluateConstant(*verbosityExpr).integer().as<
unsigned>();
1097 assert(value &&
"Slang guarantees constant verbosity parameter");
1102 moore::FinishMessageBIOp::create(builder, loc, verbosity > 1);
1106 LogicalResult visit(
const slang::ast::EventTriggerStatement &stmt) {
1108 mlir::emitError(loc) <<
"unsupported delayed event trigger";
1114 auto target =
context.convertLvalueExpression(stmt.target);
1120 Value inverted = moore::ReadOp::create(builder, loc, target);
1121 inverted = moore::NotOp::create(builder, loc, inverted);
1123 if (stmt.isNonBlocking)
1124 moore::NonBlockingAssignOp::create(builder, loc, target, inverted);
1126 moore::BlockingAssignOp::create(builder, loc, target, inverted);
1131 LogicalResult visit(
const slang::ast::WaitStatement &stmt) {
1132 auto waitOp = moore::WaitLevelOp::create(builder, loc);
1134 OpBuilder::InsertionGuard guard(builder);
1135 builder.setInsertionPointToStart(&waitOp.getBody().emplaceBlock());
1136 auto cond =
context.convertRvalueExpression(stmt.cond);
1139 cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
1140 moore::DetectLevelOp::create(builder, loc, cond);
1143 if (failed(
context.convertStatement(stmt.stmt)))
1149 LogicalResult visit(
const slang::ast::WaitForkStatement &stmt) {
1150 moore::WaitForkOp::create(builder, loc);
1155 template <
typename T>
1156 LogicalResult visit(T &&stmt) {
1157 mlir::emitError(loc,
"unsupported statement: ")
1158 << slang::ast::toString(stmt.kind);
1159 return mlir::failure();
1162 LogicalResult visitInvalid(
const slang::ast::Statement &stmt) {
1163 mlir::emitError(loc,
"invalid statement: ")
1164 << slang::ast::toString(stmt.kind);
1165 return mlir::failure();
1170LogicalResult 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.