25#include "mlir/IR/Builders.h"
26#include "mlir/IR/BuiltinTypes.h"
27#include "mlir/IR/Matchers.h"
28#include "mlir/IR/PatternMatch.h"
29#include "mlir/Interfaces/FunctionImplementation.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/ADT/TypeSwitch.h"
43bool sv::is2StateExpression(Value v) {
44 if (
auto *op = v.getDefiningOp()) {
45 if (
auto attr = op->getAttrOfType<UnitAttr>(
"twoState"))
53bool sv::isExpression(Operation *op) {
54 return isa<VerbatimExprOp, VerbatimExprSEOp, GetModportOp,
55 ReadInterfaceSignalOp, ConstantXOp, ConstantZOp, ConstantStrOp,
56 MacroRefExprOp, MacroRefExprSEOp>(op);
64 Region ®ion = symbolTableOp->getRegion(0);
69 StringAttr symbolNameId = StringAttr::get(symbolTableOp->getContext(),
70 SymbolTable::getSymbolAttrName());
71 for (Block &block : region)
72 for (Operation &nestedOp : block) {
73 auto nameAttr = nestedOp.getAttrOfType<StringAttr>(symbolNameId);
74 if (nameAttr && nameAttr.getValue() == symbol)
76 if (!nestedOp.hasTrait<OpTrait::SymbolTable>() &&
77 nestedOp.getNumRegions()) {
88 SymbolTableCollection &symbolTable) {
89 auto *refOp = symbolTable.lookupNearestSymbolFrom(op, attr);
91 return op->emitError(
"references an undefined symbol: ") << attr;
92 if (!isa<MacroDeclOp>(refOp))
93 return op->emitError(
"must reference a macro declaration");
105 for (
auto symbol : symbols) {
106 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(symbol)) {
108 return op->emitError() <<
"inner symbol reference " << innerRef
109 <<
" could not be found";
119 SymbolTableCollection &symbolTable) {
120 for (
auto symbol : symbols) {
121 if (
auto flatRef = dyn_cast<FlatSymbolRefAttr>(symbol)) {
122 auto *referencedOp = symbolTable.lookupNearestSymbolFrom(op, flatRef);
124 return op->emitOpError(
"references nonexistent symbol '")
125 << flatRef.getValue() <<
"'";
135LogicalResult VerbatimOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
147 function_ref<
void(Value, StringRef)> setNameFn) {
151 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
152 auto name = op->getAttrOfType<StringAttr>(
"format_string").getValue();
154 if (name.starts_with(
"`"))
155 name = name.drop_front();
156 name = name.take_while(isOkCharacter);
158 setNameFn(op->getResult(0), name);
161void VerbatimExprOp::getAsmResultNames(
162 function_ref<
void(Value, StringRef)> setNameFn) {
171VerbatimExprOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
176void VerbatimExprSEOp::getAsmResultNames(
177 function_ref<
void(Value, StringRef)> setNameFn) {
186VerbatimExprSEOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
195void MacroRefExprOp::getAsmResultNames(
196 function_ref<
void(Value, StringRef)> setNameFn) {
197 setNameFn(getResult(), getMacroName());
200void MacroRefExprSEOp::getAsmResultNames(
201 function_ref<
void(Value, StringRef)> setNameFn) {
202 setNameFn(getResult(), getMacroName());
207 FlatSymbolRefAttr macroName) {
209 if (
auto *result = cache->
getDefinition(macroName.getAttr()))
210 return cast<MacroDeclOp>(result);
212 auto topLevelModuleOp = op->getParentOfType<ModuleOp>();
213 return topLevelModuleOp.lookupSymbol<MacroDeclOp>(macroName.getValue());
219 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
224 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
231std::string MacroErrorOp::getMacroIdentifier() {
232 const auto *prefix =
"_ERROR";
233 auto msg = getMessage();
234 if (!msg || msg->empty())
237 std::string id(prefix);
239 for (
auto c : *msg) {
240 if (llvm::isAlnum(c))
253 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
257 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
262MacroRefExprOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
268MacroRefExprSEOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
273LogicalResult MacroDefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
278LogicalResult MacroRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
286StringRef MacroDeclOp::getMacroIdentifier() {
287 return getVerilogName().value_or(getSymName());
294void ConstantXOp::getAsmResultNames(
295 function_ref<
void(Value, StringRef)> setNameFn) {
296 SmallVector<char, 32> specialNameBuffer;
297 llvm::raw_svector_ostream specialName(specialNameBuffer);
299 setNameFn(getResult(), specialName.str());
302LogicalResult ConstantXOp::verify() {
305 return emitError(
"unsupported type");
309void ConstantZOp::getAsmResultNames(
310 function_ref<
void(Value, StringRef)> setNameFn) {
311 SmallVector<char, 32> specialNameBuffer;
312 llvm::raw_svector_ostream specialName(specialNameBuffer);
314 setNameFn(getResult(), specialName.str());
317LogicalResult ConstantZOp::verify() {
320 return emitError(
"unsupported type");
328void LocalParamOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
330 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
331 if (!nameAttr.getValue().empty())
332 setNameFn(getResult(), nameAttr.getValue());
335LogicalResult LocalParamOp::verify() {
337 return hw::checkParameterInContext(
347 std::optional<OpAsmParser::UnresolvedOperand> &initValue,
348 mlir::Type &initType) {
349 if (!initValue.has_value())
352 hw::InOutType ioType = dyn_cast<hw::InOutType>(regType);
354 return p.emitError(p.getCurrentLocation(),
"expected inout type for reg");
356 initType = ioType.getElementType();
361 mlir::Type regType, mlir::Value initValue,
362 mlir::Type initType) {}
364void RegOp::build(OpBuilder &builder, OperationState &odsState,
365 Type
elementType, StringAttr name, hw::InnerSymAttr innerSym,
366 mlir::Value initValue) {
368 name = builder.getStringAttr(
"");
369 odsState.addAttribute(
"name", name);
373 odsState.addTypes(hw::InOutType::get(
elementType));
375 odsState.addOperands(initValue);
380void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
382 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
383 if (!nameAttr.getValue().empty())
384 setNameFn(getResult(), nameAttr.getValue());
387std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
390LogicalResult RegOp::canonicalize(
RegOp op, PatternRewriter &rewriter) {
396 if (op.getInnerSymAttr())
400 for (
auto *user : op.getResult().getUsers())
405 for (
auto *user :
llvm::make_early_inc_range(op.getResult().getUsers()))
406 rewriter.eraseOp(user);
409 rewriter.eraseOp(op);
417void LogicOp::build(OpBuilder &builder, OperationState &odsState,
419 hw::InnerSymAttr innerSym) {
421 name = builder.getStringAttr(
"");
422 odsState.addAttribute(
"name", name);
426 odsState.addTypes(hw::InOutType::get(
elementType));
431void LogicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
433 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
434 if (!nameAttr.getValue().empty())
435 setNameFn(getResult(), nameAttr.getValue());
438std::optional<size_t> LogicOp::getTargetResultIndex() {
return 0; }
448void IfDefOp::build(OpBuilder &builder, OperationState &result, StringRef cond,
449 std::function<
void()> thenCtor,
450 std::function<
void()> elseCtor) {
451 build(builder, result, builder.getStringAttr(cond), std::move(thenCtor),
452 std::move(elseCtor));
455void IfDefOp::build(OpBuilder &builder, OperationState &result, StringAttr cond,
456 std::function<
void()> thenCtor,
457 std::function<
void()> elseCtor) {
458 build(builder, result, FlatSymbolRefAttr::get(builder.getContext(), cond),
459 std::move(thenCtor), std::move(elseCtor));
462void IfDefOp::build(OpBuilder &builder, OperationState &result,
463 FlatSymbolRefAttr cond, std::function<
void()> thenCtor,
464 std::function<
void()> elseCtor) {
465 build(builder, result, MacroIdentAttr::get(builder.getContext(), cond),
466 std::move(thenCtor), std::move(elseCtor));
469void IfDefOp::build(OpBuilder &builder, OperationState &result,
470 MacroIdentAttr cond, std::function<
void()> thenCtor,
471 std::function<
void()> elseCtor) {
472 OpBuilder::InsertionGuard guard(builder);
474 result.addAttribute(
"cond", cond);
475 builder.createBlock(result.addRegion());
481 Region *elseRegion = result.addRegion();
483 builder.createBlock(elseRegion);
488LogicalResult IfDefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
495 if (!op.getThenBlock()->empty())
498 if (op.hasElse() && !op.getElseBlock()->empty())
501 rewriter.eraseOp(op);
505LogicalResult IfDefOp::canonicalize(
IfDefOp op, PatternRewriter &rewriter) {
514 ArrayRef<StringAttr> macroSymbols,
515 llvm::function_ref<
void(StringAttr, std::function<
void()>,
516 std::function<
void()>)>
518 llvm::function_ref<
void(
size_t)> thenCtor,
519 llvm::function_ref<
void()> defaultCtor) {
522 std::function<void(
size_t)> buildNested = [&](
size_t index) {
523 if (index >= macroSymbols.size()) {
539 [&, index]() { buildNested(index + 1); });
549void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
550 StringRef cond, std::function<
void()> thenCtor,
551 std::function<
void()> elseCtor) {
552 build(builder, result, builder.getStringAttr(cond), std::move(thenCtor),
553 std::move(elseCtor));
556void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
557 StringAttr cond, std::function<
void()> thenCtor,
558 std::function<
void()> elseCtor) {
559 build(builder, result, FlatSymbolRefAttr::get(builder.getContext(), cond),
560 std::move(thenCtor), std::move(elseCtor));
563void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
564 FlatSymbolRefAttr cond,
565 std::function<
void()> thenCtor,
566 std::function<
void()> elseCtor) {
567 build(builder, result, MacroIdentAttr::get(builder.getContext(), cond),
568 std::move(thenCtor), std::move(elseCtor));
571void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
573 std::function<
void()> thenCtor,
574 std::function<
void()> elseCtor) {
575 OpBuilder::InsertionGuard guard(builder);
577 result.addAttribute(
"cond", cond);
578 builder.createBlock(result.addRegion());
584 Region *elseRegion = result.addRegion();
586 builder.createBlock(elseRegion);
591LogicalResult IfDefProceduralOp::canonicalize(IfDefProceduralOp op,
592 PatternRewriter &rewriter) {
597IfDefProceduralOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
605void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
606 std::function<
void()> thenCtor,
607 std::function<
void()> elseCtor) {
608 OpBuilder::InsertionGuard guard(builder);
610 result.addOperands(cond);
611 builder.createBlock(result.addRegion());
617 Region *elseRegion = result.addRegion();
619 builder.createBlock(elseRegion);
627 assert(llvm::hasSingleElement(region) &&
"expected single-region block");
628 Block *fromBlock = ®ion.front();
630 op->getBlock()->getOperations().splice(Block::iterator(op),
631 fromBlock->getOperations());
634LogicalResult IfOp::canonicalize(IfOp op, PatternRewriter &rewriter) {
639 if (
auto constant = op.getCond().getDefiningOp<
hw::ConstantOp>()) {
641 if (constant.getValue().isAllOnes())
643 else if (!op.getElseRegion().empty())
646 rewriter.eraseOp(op);
652 if (!op.getThenBlock()->empty() && op.hasElse() &&
653 op.getElseBlock()->empty()) {
654 rewriter.eraseBlock(op.getElseBlock());
661 if (!op.getThenBlock()->empty())
665 if (!op.hasElse() || op.getElseBlock()->empty()) {
666 rewriter.eraseOp(op);
677 auto *thenBlock = op.getThenBlock(), *elseBlock = op.getElseBlock();
680 thenBlock->getOperations().splice(thenBlock->end(),
681 elseBlock->getOperations());
682 rewriter.eraseBlock(elseBlock);
692AlwaysOp::Condition AlwaysOp::getCondition(
size_t idx) {
693 return Condition{EventControl(cast<IntegerAttr>(getEvents()[idx]).
getInt()),
697void AlwaysOp::build(OpBuilder &builder, OperationState &result,
698 ArrayRef<sv::EventControl> events, ArrayRef<Value> clocks,
699 std::function<
void()> bodyCtor) {
700 assert(events.size() == clocks.size() &&
701 "mismatch between event and clock list");
702 OpBuilder::InsertionGuard guard(builder);
704 SmallVector<Attribute> eventAttrs;
705 for (
auto event : events)
706 eventAttrs.push_back(
707 builder.getI32IntegerAttr(static_cast<int32_t>(event)));
708 result.addAttribute(
"events", builder.getArrayAttr(eventAttrs));
709 result.addOperands(clocks);
712 builder.createBlock(result.addRegion());
720LogicalResult AlwaysOp::verify() {
721 if (getEvents().size() != getNumOperands())
722 return emitError(
"different number of operands and events");
727 OpAsmParser &p, Attribute &eventsAttr,
728 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &clocksOperands) {
731 SmallVector<Attribute> events;
733 auto loc = p.getCurrentLocation();
735 if (!p.parseOptionalKeyword(&keyword)) {
737 auto kind = sv::symbolizeEventControl(keyword);
738 if (!kind.has_value())
739 return p.emitError(loc,
"expected 'posedge', 'negedge', or 'edge'");
740 auto eventEnum =
static_cast<int32_t
>(*kind);
741 events.push_back(p.getBuilder().getI32IntegerAttr(eventEnum));
743 clocksOperands.push_back({});
744 if (p.parseOperand(clocksOperands.back()))
747 if (failed(p.parseOptionalComma()))
749 if (p.parseKeyword(&keyword))
753 eventsAttr = p.getBuilder().getArrayAttr(events);
758 OperandRange operands) {
759 for (
size_t i = 0, e = op.getNumConditions(); i != e; ++i) {
762 auto cond = op.getCondition(i);
763 p << stringifyEventControl(cond.event);
765 p.printOperand(cond.value);
773void AlwaysFFOp::build(OpBuilder &builder, OperationState &result,
774 EventControl clockEdge, Value clock,
775 std::function<
void()> bodyCtor) {
776 OpBuilder::InsertionGuard guard(builder);
779 "clockEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(clockEdge)));
780 result.addOperands(clock);
783 builder.getI32IntegerAttr(
static_cast<int32_t
>(ResetType::NoReset)));
786 builder.createBlock(result.addRegion());
795void AlwaysFFOp::build(OpBuilder &builder, OperationState &result,
796 EventControl clockEdge, Value clock,
797 ResetType resetStyle, EventControl resetEdge,
798 Value reset, std::function<
void()> bodyCtor,
799 std::function<
void()> resetCtor) {
800 OpBuilder::InsertionGuard guard(builder);
803 "clockEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(clockEdge)));
804 result.addOperands(clock);
805 result.addAttribute(
"resetStyle", builder.getI32IntegerAttr(
806 static_cast<int32_t
>(resetStyle)));
808 "resetEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(resetEdge)));
809 result.addOperands(reset);
812 builder.createBlock(result.addRegion());
818 builder.createBlock(result.addRegion());
828void AlwaysCombOp::build(OpBuilder &builder, OperationState &result,
829 std::function<
void()> bodyCtor) {
830 OpBuilder::InsertionGuard guard(builder);
832 builder.createBlock(result.addRegion());
842void InitialOp::build(OpBuilder &builder, OperationState &result,
843 std::function<
void()> bodyCtor) {
844 OpBuilder::InsertionGuard guard(builder);
846 builder.createBlock(result.addRegion());
869 llvm_unreachable(
"invalid casez PatternBit");
874 return CasePatternBit(
unsigned(intAttr.getValue()[bitNumber * 2]) +
875 2 *
unsigned(intAttr.getValue()[bitNumber * 2 + 1]));
879 for (
size_t i = 0, e = getWidth(); i != e; ++i)
886 for (
size_t i = 0, e = getWidth(); i != e; ++i)
892 SmallVector<CasePatternBit> result;
893 result.reserve(value.getBitWidth());
894 for (
size_t i = 0, e = value.getBitWidth(); i != e; ++i)
912 APInt
pattern(bits.size() * 2, 0);
913 for (
auto elt : llvm::reverse(bits)) {
917 auto patternType = IntegerType::get(
context, bits.size() * 2);
921auto CaseOp::getCases() -> SmallVector<CaseInfo, 4> {
922 SmallVector<CaseInfo, 4> result;
923 assert(getCasePatterns().size() == getNumRegions() &&
924 "case pattern / region count mismatch");
925 size_t nextRegion = 0;
926 for (
auto elt : getCasePatterns()) {
927 llvm::TypeSwitch<Attribute>(elt)
928 .Case<hw::EnumFieldAttr>([&](
auto enumAttr) {
929 result.push_back({std::make_unique<CaseEnumPattern>(enumAttr),
930 &getRegion(nextRegion++).front()});
932 .Case<CaseExprPatternAttr>([&](
auto exprAttr) {
933 result.push_back({std::make_unique<CaseExprPattern>(getContext()),
934 &getRegion(nextRegion++).front()});
936 .Case<IntegerAttr>([&](
auto intAttr) {
937 result.push_back({std::make_unique<CaseBitPattern>(intAttr),
938 &getRegion(nextRegion++).front()});
940 .Case<CaseDefaultPattern::AttrType>([&](
auto) {
941 result.push_back({std::make_unique<CaseDefaultPattern>(getContext()),
942 &getRegion(nextRegion++).front()});
945 assert(
false &&
"invalid case pattern attribute type");
953 return cast<hw::EnumFieldAttr>(
enumAttr).getField();
963ParseResult CaseOp::parse(OpAsmParser &parser, OperationState &result) {
964 auto &builder = parser.getBuilder();
966 OpAsmParser::UnresolvedOperand condOperand;
969 auto loc = parser.getCurrentLocation();
972 if (!parser.parseOptionalKeyword(&keyword, {
"case",
"casex",
"casez"})) {
973 auto kind = symbolizeCaseStmtType(keyword);
974 auto caseEnum =
static_cast<int32_t
>(kind.value());
975 result.addAttribute(
"caseStyle", builder.getI32IntegerAttr(caseEnum));
979 if (!parser.parseOptionalKeyword(
980 &keyword, {
"plain",
"priority",
"unique",
"unique0"})) {
981 auto kind = symbolizeValidationQualifierTypeEnum(keyword);
982 result.addAttribute(
"validationQualifier",
983 ValidationQualifierTypeEnumAttr::get(
984 builder.getContext(), kind.value()));
987 if (parser.parseOperand(condOperand) || parser.parseColonType(condType) ||
988 parser.parseOptionalAttrDict(result.attributes) ||
989 parser.resolveOperand(condOperand, condType, result.operands))
994 hw::EnumType enumType = dyn_cast<hw::EnumType>(canonicalCondType);
995 unsigned condWidth = 0;
997 if (!result.operands[0].getType().isSignlessInteger())
998 return parser.emitError(loc,
"condition must have signless integer type");
999 condWidth = condType.getIntOrFloatBitWidth();
1003 SmallVector<Attribute> casePatterns;
1004 SmallVector<CasePatternBit, 16> caseBits;
1006 mlir::OptionalParseResult caseValueParseResult;
1007 OpAsmParser::UnresolvedOperand caseValueOperand;
1008 if (succeeded(parser.parseOptionalKeyword(
"default"))) {
1009 casePatterns.push_back(CaseDefaultPattern(parser.getContext()).attr());
1010 }
else if (failed(parser.parseOptionalKeyword(
"case"))) {
1013 }
else if (enumType) {
1017 if (parser.parseKeyword(&caseVal))
1020 if (!enumType.contains(caseVal))
1021 return parser.emitError(loc)
1022 <<
"case value '" + caseVal +
"' is not a member of enum type "
1024 casePatterns.push_back(
1025 hw::EnumFieldAttr::get(parser.getEncodedSourceLoc(loc),
1026 builder.getStringAttr(caseVal), condType));
1027 }
else if ((caseValueParseResult =
1028 parser.parseOptionalOperand(caseValueOperand))
1030 if (failed(caseValueParseResult.value()) ||
1031 parser.resolveOperand(caseValueOperand, condType, result.operands))
1033 casePatterns.push_back(CaseExprPattern(parser.getContext()).attr());
1038 loc = parser.getCurrentLocation();
1039 if (parser.parseKeyword(&caseVal))
1042 if (caseVal.front() !=
'b')
1043 return parser.emitError(loc,
"expected case value starting with 'b'");
1044 caseVal = caseVal.drop_front();
1047 for (; !caseVal.empty(); caseVal = caseVal.drop_front()) {
1049 switch (caseVal.front()) {
1063 return parser.emitError(loc,
"unexpected case bit '")
1064 << caseVal.front() <<
"'";
1066 caseBits.push_back(bit);
1069 if (caseVal.size() > condWidth)
1070 return parser.emitError(loc,
"too many bits specified in pattern");
1071 std::reverse(caseBits.begin(), caseBits.end());
1074 if (caseBits.size() < condWidth)
1077 auto resultPattern = CaseBitPattern(caseBits, builder.getContext());
1078 casePatterns.push_back(resultPattern.attr());
1083 auto caseRegion = std::make_unique<Region>();
1084 if (parser.parseColon() || parser.parseRegion(*caseRegion))
1086 result.addRegion(std::move(caseRegion));
1089 result.addAttribute(
"casePatterns", builder.getArrayAttr(casePatterns));
1093void CaseOp::print(OpAsmPrinter &p) {
1095 if (getCaseStyle() == CaseStmtType::CaseXStmt)
1097 else if (getCaseStyle() == CaseStmtType::CaseZStmt)
1100 if (getValidationQualifier() !=
1101 ValidationQualifierTypeEnum::ValidationQualifierPlain)
1102 p << stringifyValidationQualifierTypeEnum(getValidationQualifier()) <<
' ';
1104 p << getCond() <<
" : " << getCond().getType();
1105 p.printOptionalAttrDict(
1106 (*this)->getAttrs(),
1107 {
"casePatterns",
"caseStyle",
"validationQualifier"});
1109 size_t caseValueIndex = 0;
1110 for (
auto &caseInfo : getCases()) {
1112 auto &
pattern = caseInfo.pattern;
1114 llvm::TypeSwitch<CasePattern *>(
pattern.get())
1115 .Case<CaseBitPattern>([&](
auto bitPattern) {
1117 for (
size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
1118 p <<
getLetter(bitPattern->getBit(e - bit - 1));
1120 .Case<CaseEnumPattern>([&](
auto enumPattern) {
1121 p <<
"case " << enumPattern->getFieldValue();
1123 .Case<CaseExprPattern>([&](
auto) {
1125 p.printOperand(getCaseValues()[caseValueIndex++]);
1127 .Case<CaseDefaultPattern>([&](
auto) { p <<
"default"; })
1128 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
1131 p.printRegion(*caseInfo.block->getParent(),
false,
1136LogicalResult CaseOp::verify() {
1139 return emitError(
"condition must have either integer or enum type");
1142 if (getCasePatterns().size() != getNumRegions())
1143 return emitOpError(
"case pattern / region count mismatch");
1150 OpBuilder &builder, OperationState &result, CaseStmtType caseStyle,
1151 ValidationQualifierTypeEnum validationQualifier, Value cond,
1153 std::function<std::unique_ptr<CasePattern>(
size_t)> caseCtor) {
1154 result.addOperands(cond);
1155 result.addAttribute(
"caseStyle",
1156 CaseStmtTypeAttr::get(builder.getContext(), caseStyle));
1157 result.addAttribute(
"validationQualifier",
1158 ValidationQualifierTypeEnumAttr::get(
1159 builder.getContext(), validationQualifier));
1160 SmallVector<Attribute> casePatterns;
1162 OpBuilder::InsertionGuard guard(builder);
1165 for (
size_t i = 0, e = numCases; i != e; ++i) {
1166 builder.createBlock(result.addRegion());
1167 casePatterns.push_back(caseCtor(i)->attr());
1170 result.addAttribute(
"casePatterns", builder.getArrayAttr(casePatterns));
1174LogicalResult CaseOp::canonicalize(CaseOp op, PatternRewriter &rewriter) {
1175 if (op.getCaseStyle() == CaseStmtType::CaseStmt)
1177 if (isa<hw::EnumType>(op.getCond().getType()))
1180 auto caseInfo = op.getCases();
1181 bool noXZ = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1182 return !ci.pattern.get()->hasX() && !ci.pattern.get()->hasZ();
1184 bool noX = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1185 if (isa<CaseDefaultPattern>(ci.pattern))
1187 return !ci.pattern.get()->hasX();
1189 bool noZ = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1190 if (isa<CaseDefaultPattern>(ci.pattern))
1192 return !ci.pattern.get()->hasZ();
1195 if (op.getCaseStyle() == CaseStmtType::CaseXStmt) {
1197 rewriter.modifyOpInPlace(op, [&]() {
1198 op.setCaseStyleAttr(
1199 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseStmt));
1204 rewriter.modifyOpInPlace(op, [&]() {
1205 op.setCaseStyleAttr(
1206 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseZStmt));
1212 if (op.getCaseStyle() == CaseStmtType::CaseZStmt && noZ) {
1213 rewriter.modifyOpInPlace(op, [&]() {
1214 op.setCaseStyleAttr(
1215 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseStmt));
1227void OrderedOutputOp::build(OpBuilder &builder, OperationState &result,
1228 std::function<
void()> body) {
1229 OpBuilder::InsertionGuard guard(builder);
1231 builder.createBlock(result.addRegion());
1242void ForOp::build(OpBuilder &builder, OperationState &result,
1243 int64_t lowerBound, int64_t upperBound, int64_t step,
1244 IntegerType type, StringRef name,
1245 llvm::function_ref<
void(BlockArgument)> body) {
1249 build(builder, result, lb, ub, st, name, body);
1251void ForOp::build(OpBuilder &builder, OperationState &result, Value lowerBound,
1252 Value upperBound, Value step, StringRef name,
1253 llvm::function_ref<
void(BlockArgument)> body) {
1254 OpBuilder::InsertionGuard guard(builder);
1255 build(builder, result, lowerBound, upperBound, step, name);
1256 auto *region = result.regions.front().get();
1257 builder.createBlock(region);
1258 BlockArgument blockArgument =
1259 region->addArgument(lowerBound.getType(), result.location);
1262 body(blockArgument);
1265void ForOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1267 auto *block = ®ion.front();
1268 setNameFn(block->getArgument(0), getInductionVarNameAttr());
1271ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
1272 auto &builder = parser.getBuilder();
1275 OpAsmParser::Argument inductionVariable;
1276 OpAsmParser::UnresolvedOperand lb, ub, step;
1278 SmallVector<OpAsmParser::Argument, 4> regionArgs;
1281 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
1283 parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
1284 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
1285 parser.parseOperand(step) || parser.parseColon() ||
1286 parser.parseType(type))
1289 regionArgs.push_back(inductionVariable);
1292 regionArgs.front().type = type;
1293 if (parser.resolveOperand(lb, type, result.operands) ||
1294 parser.resolveOperand(ub, type, result.operands) ||
1295 parser.resolveOperand(step, type, result.operands))
1299 Region *body = result.addRegion();
1300 if (parser.parseRegion(*body, regionArgs))
1304 if (parser.parseOptionalAttrDict(result.attributes))
1307 if (!inductionVariable.ssaName.name.empty()) {
1308 if (!
isdigit(inductionVariable.ssaName.name[1]))
1310 result.attributes.append(
1311 {builder.getStringAttr(
"inductionVarName"),
1312 builder.getStringAttr(inductionVariable.ssaName.name.drop_front())});
1318void ForOp::print(OpAsmPrinter &p) {
1319 p <<
" " << getInductionVar() <<
" = " << getLowerBound() <<
" to "
1320 << getUpperBound() <<
" step " << getStep();
1321 p <<
" : " << getInductionVar().getType() <<
' ';
1322 p.printRegion(getRegion(),
1325 p.printOptionalAttrDict((*this)->getAttrs(), {
"inductionVarName"});
1328LogicalResult ForOp::canonicalize(
ForOp op, PatternRewriter &rewriter) {
1330 if (matchPattern(op.getLowerBound(), mlir::m_ConstantInt(&lb)) &&
1331 matchPattern(op.getUpperBound(), mlir::m_ConstantInt(&ub)) &&
1332 matchPattern(op.getStep(), mlir::m_ConstantInt(&step)) &&
1335 rewriter.replaceAllUsesWith(op.getInductionVar(), op.getLowerBound());
1337 rewriter.eraseOp(op);
1347LogicalResult BPAssignOp::verify() {
1348 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1350 "Verilog disallows procedural assignment to a net type (did you intend "
1351 "to use a variable type, e.g., sv.reg?)");
1355LogicalResult PAssignOp::verify() {
1356 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1358 "Verilog disallows procedural assignment to a net type (did you intend "
1359 "to use a variable type, e.g., sv.reg?)");
1372 static std::optional<ArraySlice> getArraySlice(Value v) {
1373 auto *op = v.getDefiningOp();
1375 return std::nullopt;
1376 return TypeSwitch<Operation *, std::optional<ArraySlice>>(op)
1377 .Case<hw::ArrayGetOp, ArrayIndexInOutOp>(
1378 [](
auto arrayIndex) -> std::optional<ArraySlice> {
1380 arrayIndex.getIndex()
1381 .template getDefiningOp<hw::ConstantOp>();
1383 return std::nullopt;
1384 return ArraySlice{arrayIndex.getInput(),
1389 -> std::optional<ArraySlice> {
1390 auto constant = slice.getLowIndex().getDefiningOp<
hw::ConstantOp>();
1392 return std::nullopt;
1394 slice.getInput(), constant,
1396 hw::type_cast<hw::ArrayType>(slice.getType()).getNumElements()};
1398 .Case<sv::IndexedPartSelectInOutOp>(
1399 [](sv::IndexedPartSelectInOutOp index)
1400 -> std::optional<ArraySlice> {
1402 if (!constant || index.getDecrement())
1403 return std::nullopt;
1404 return ArraySlice{index.getInput(),
1408 .Default([](
auto) {
return std::nullopt; });
1412 static std::optional<std::pair<ArraySlice, ArraySlice>>
1413 getAssignedRange(Operation *op) {
1414 assert((isa<PAssignOp, BPAssignOp>(op) &&
"assignments are expected"));
1415 auto srcRange = ArraySlice::getArraySlice(op->getOperand(1));
1417 return std::nullopt;
1418 auto destRange = ArraySlice::getArraySlice(op->getOperand(0));
1420 return std::nullopt;
1422 return std::make_pair(*destRange, *srcRange);
1433template <
typename AssignTy>
1435 PatternRewriter &rewriter) {
1437 auto assignedRangeOpt = ArraySlice::getAssignedRange(op);
1438 if (!assignedRangeOpt)
1441 auto [dest, src] = *assignedRangeOpt;
1442 AssignTy nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1443 bool changed =
false;
1444 SmallVector<Location> loc{op.getLoc()};
1446 while (nextAssign) {
1447 auto nextAssignedRange = ArraySlice::getAssignedRange(nextAssign);
1448 if (!nextAssignedRange)
1450 auto [nextDest, nextSrc] = *nextAssignedRange;
1452 if (dest.array != nextDest.array || src.array != nextSrc.array ||
1453 !
hw::isOffset(dest.start, nextDest.start, dest.size) ||
1457 dest.size += nextDest.size;
1458 src.size += nextSrc.size;
1460 loc.push_back(nextAssign.getLoc());
1461 rewriter.eraseOp(nextAssign);
1462 nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1469 auto resultType = hw::ArrayType::get(
1470 hw::type_cast<hw::ArrayType>(src.array.getType()).getElementType(),
1472 auto newDest = sv::IndexedPartSelectInOutOp::create(
1473 rewriter, op.getLoc(), dest.array, dest.start, dest.size);
1475 src.array, src.start);
1476 auto newLoc = rewriter.getFusedLoc(loc);
1477 auto newOp = rewriter.replaceOpWithNewOp<AssignTy>(op, newDest, newSrc);
1478 newOp->setLoc(newLoc);
1482LogicalResult PAssignOp::canonicalize(PAssignOp op, PatternRewriter &rewriter) {
1486LogicalResult BPAssignOp::canonicalize(BPAssignOp op,
1487 PatternRewriter &rewriter) {
1495void InterfaceOp::build(OpBuilder &builder, OperationState &result,
1496 StringRef sym_name, std::function<
void()> body) {
1497 OpBuilder::InsertionGuard guard(builder);
1499 result.addAttribute(::SymbolTable::getSymbolAttrName(),
1500 builder.getStringAttr(sym_name));
1501 builder.createBlock(result.addRegion());
1506ModportType InterfaceOp::getModportType(StringRef modportName) {
1507 assert(lookupSymbol<InterfaceModportOp>(modportName) &&
1508 "Modport symbol not found.");
1509 auto *ctxt = getContext();
1510 return ModportType::get(
1512 SymbolRefAttr::get(ctxt, getSymName(),
1513 {SymbolRefAttr::get(ctxt, modportName)}));
1516Type InterfaceOp::getSignalType(StringRef signalName) {
1517 InterfaceSignalOp signal = lookupSymbol<InterfaceSignalOp>(signalName);
1518 assert(signal &&
"Interface signal symbol not found.");
1519 return signal.getType();
1523 ArrayAttr &portsAttr) {
1525 auto *
context = parser.getBuilder().getContext();
1527 SmallVector<Attribute, 8> ports;
1528 auto parseElement = [&]() -> ParseResult {
1529 auto direction = ModportDirectionAttr::parse(parser, {});
1533 FlatSymbolRefAttr signal;
1534 if (parser.parseAttribute(signal))
1537 ports.push_back(ModportStructAttr::get(
1538 context, cast<ModportDirectionAttr>(direction), signal));
1541 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1545 portsAttr = ArrayAttr::get(
context, ports);
1550 ArrayAttr portsAttr) {
1552 llvm::interleaveComma(portsAttr, p, [&](Attribute attr) {
1553 auto port = cast<ModportStructAttr>(attr);
1554 p << stringifyEnum(port.getDirection().getValue());
1556 p.printSymbolName(port.getSignal().getRootReference().getValue());
1561void InterfaceSignalOp::build(mlir::OpBuilder &builder,
1562 ::mlir::OperationState &state, StringRef name,
1564 build(builder, state, name, mlir::TypeAttr::get(type));
1567void InterfaceModportOp::build(OpBuilder &builder, OperationState &state,
1568 StringRef name, ArrayRef<StringRef> inputs,
1569 ArrayRef<StringRef> outputs) {
1570 auto *ctxt = builder.getContext();
1571 SmallVector<Attribute, 8> directions;
1572 auto inputDir = ModportDirectionAttr::get(ctxt, ModportDirection::input);
1573 auto outputDir = ModportDirectionAttr::get(ctxt, ModportDirection::output);
1574 for (
auto input : inputs)
1575 directions.push_back(ModportStructAttr::
get(
1576 ctxt, inputDir, SymbolRefAttr::
get(ctxt, input)));
1577 for (
auto output : outputs)
1578 directions.push_back(ModportStructAttr::
get(
1579 ctxt, outputDir, SymbolRefAttr::
get(ctxt, output)));
1580 build(builder, state, name, ArrayAttr::get(ctxt, directions));
1583std::optional<size_t> InterfaceInstanceOp::getTargetResultIndex() {
1585 return std::nullopt;
1590void InterfaceInstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
1591 setNameFn(getResult(),
getName());
1595LogicalResult InterfaceInstanceOp::verify() {
1597 return emitOpError(
"requires non-empty name");
1602InterfaceInstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1603 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1605 return emitError(
"sv.interface.instance must exist within a region "
1606 "which has a symbol table.");
1607 auto ifaceTy = getType();
1608 auto *referencedOp =
1609 symbolTable.lookupSymbolIn(symtable, ifaceTy.getInterface());
1611 return emitError(
"Symbol not found: ") << ifaceTy.getInterface() <<
".";
1612 if (!isa<InterfaceOp>(referencedOp))
1613 return emitError(
"Symbol ")
1614 << ifaceTy.getInterface() <<
" is not an InterfaceOp.";
1621GetModportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1622 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1624 return emitError(
"sv.interface.instance must exist within a region "
1625 "which has a symbol table.");
1627 auto ifaceTy = getType();
1628 auto *referencedOp =
1629 symbolTable.lookupSymbolIn(symtable, ifaceTy.getModport());
1631 return emitError(
"Symbol not found: ") << ifaceTy.getModport() <<
".";
1632 if (!isa<InterfaceModportOp>(referencedOp))
1633 return emitError(
"Symbol ")
1634 << ifaceTy.getModport() <<
" is not an InterfaceModportOp.";
1638void GetModportOp::build(OpBuilder &builder, OperationState &state, Value value,
1640 auto ifaceTy = dyn_cast<InterfaceType>(value.getType());
1641 assert(ifaceTy &&
"GetModportOp expects an InterfaceType.");
1642 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), field);
1644 SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(), fieldAttr);
1645 build(builder, state, ModportType::get(builder.getContext(), modportSym),
1653 return dyn_cast_or_null<InterfaceModportOp>(
1657void ReadInterfaceSignalOp::build(OpBuilder &builder, OperationState &state,
1658 Value iface, StringRef signalName) {
1659 auto ifaceTy = dyn_cast<InterfaceType>(iface.getType());
1660 assert(ifaceTy &&
"ReadInterfaceSignalOp expects an InterfaceType.");
1661 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), signalName);
1662 InterfaceOp ifaceDefOp = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1663 iface.getDefiningOp(), ifaceTy.getInterface());
1665 "ReadInterfaceSignalOp could not resolve an InterfaceOp.");
1666 build(builder, state, ifaceDefOp.getSignalType(signalName), iface, fieldAttr);
1673 return dyn_cast_or_null<InterfaceSignalOp>(
1678 FlatSymbolRefAttr &signalName) {
1679 SymbolRefAttr fullSym;
1680 if (p.parseAttribute(fullSym) || fullSym.getNestedReferences().size() != 1)
1683 auto *ctxt = p.getBuilder().getContext();
1684 ifaceTy = InterfaceType::get(
1685 ctxt, FlatSymbolRefAttr::get(fullSym.getRootReference()));
1686 signalName = FlatSymbolRefAttr::get(fullSym.getLeafReference());
1691 FlatSymbolRefAttr signalName) {
1692 InterfaceType ifaceTy = dyn_cast<InterfaceType>(type);
1693 assert(ifaceTy &&
"Expected an InterfaceType");
1694 auto sym = SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(),
1700 auto ifaceTy = dyn_cast<InterfaceType>(ifaceVal.getType());
1703 InterfaceOp iface = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1704 ifaceVal.getDefiningOp(), ifaceTy.getInterface());
1707 InterfaceSignalOp signal = iface.lookupSymbol<InterfaceSignalOp>(signalName);
1715 FlatSymbolRefAttr
interface = getInterfaceType().getInterface();
1720 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1721 if (!topLevelModuleOp)
1724 return topLevelModuleOp.lookupSymbol(interface);
1727LogicalResult AssignInterfaceSignalOp::verify() {
1731LogicalResult ReadInterfaceSignalOp::verify() {
1739void WireOp::build(OpBuilder &builder, OperationState &odsState,
1741 hw::InnerSymAttr innerSym) {
1743 name = builder.getStringAttr(
"");
1748 odsState.addAttribute(
"name", name);
1754void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
1756 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
1757 if (!nameAttr.getValue().empty())
1758 setNameFn(getResult(), nameAttr.getValue());
1761std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
1764LogicalResult WireOp::canonicalize(
WireOp wire, PatternRewriter &rewriter) {
1770 if (wire.getInnerSymAttr())
1775 SmallVector<sv::ReadInOutOp> reads;
1778 for (
auto *user : wire->getUsers()) {
1779 if (
auto read = dyn_cast<sv::ReadInOutOp>(user)) {
1780 reads.push_back(read);
1785 auto assign = dyn_cast<sv::AssignOp>(user);
1788 if (!assign || write)
1804 connected = ConstantZOp::create(
1805 rewriter, wire.getLoc(),
1806 cast<InOutType>(wire.getResult().getType()).getElementType());
1807 }
else if (isa<hw::HWModuleOp>(
write->getParentOp()))
1808 connected =
write.getSrc();
1815 if (
auto *connectedOp = connected.getDefiningOp())
1816 if (!wire.getName().empty())
1817 rewriter.modifyOpInPlace(connectedOp, [&] {
1818 connectedOp->setAttr(
"sv.namehint", wire.getNameAttr());
1822 for (
auto read : reads)
1823 rewriter.replaceOp(
read, connected);
1827 rewriter.eraseOp(write);
1828 rewriter.eraseOp(wire);
1838 auto elemTy = cast<hw::InOutType>(type).getElementType();
1839 if (isa<IntegerType>(elemTy))
1840 return hw::InOutType::get(IntegerType::get(type.getContext(), width));
1841 if (isa<hw::ArrayType>(elemTy))
1842 return hw::InOutType::get(hw::ArrayType::get(
1843 cast<hw::ArrayType>(elemTy).getElementType(), width));
1847LogicalResult IndexedPartSelectInOutOp::inferReturnTypes(
1848 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1849 DictionaryAttr attrs, mlir::PropertyRef properties,
1850 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1851 Adaptor adaptor(operands, attrs, properties, regions);
1852 auto width = adaptor.getWidthAttr();
1857 width.getValue().getZExtValue());
1860 results.push_back(typ);
1864LogicalResult IndexedPartSelectInOutOp::verify() {
1865 unsigned inputWidth = 0, resultWidth = 0;
1867 auto inputElemTy = cast<InOutType>(getInput().getType()).getElementType();
1868 auto resultElemTy = cast<InOutType>(getType()).getElementType();
1869 if (
auto i = dyn_cast<IntegerType>(inputElemTy))
1870 inputWidth = i.getWidth();
1871 else if (
auto i = hw::type_cast<hw::ArrayType>(inputElemTy))
1872 inputWidth = i.getNumElements();
1874 return emitError(
"input element type must be Integer or Array");
1876 if (
auto resType = dyn_cast<IntegerType>(resultElemTy))
1877 resultWidth = resType.getWidth();
1878 else if (
auto resType = hw::type_cast<hw::ArrayType>(resultElemTy))
1879 resultWidth = resType.getNumElements();
1881 return emitError(
"result element type must be Integer or Array");
1883 if (opWidth > inputWidth)
1884 return emitError(
"slice width should not be greater than input width");
1885 if (opWidth != resultWidth)
1886 return emitError(
"result width must be equal to slice width");
1890OpFoldResult IndexedPartSelectInOutOp::fold(FoldAdaptor) {
1891 if (getType() == getInput().getType())
1900LogicalResult IndexedPartSelectOp::inferReturnTypes(
1901 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1902 DictionaryAttr attrs, mlir::PropertyRef properties,
1903 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1904 Adaptor adaptor(operands, attrs, properties, regions);
1905 auto width = adaptor.getWidthAttr();
1909 results.push_back(IntegerType::get(
context, width.getInt()));
1913LogicalResult IndexedPartSelectOp::verify() {
1916 unsigned resultWidth = cast<IntegerType>(getType()).getWidth();
1917 unsigned inputWidth = cast<IntegerType>(getInput().getType()).getWidth();
1919 if (opWidth > inputWidth)
1920 return emitError(
"slice width should not be greater than input width");
1921 if (opWidth != resultWidth)
1922 return emitError(
"result width must be equal to slice width");
1930LogicalResult StructFieldInOutOp::inferReturnTypes(
1931 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1932 DictionaryAttr attrs, mlir::PropertyRef properties,
1933 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1934 Adaptor adaptor(operands, attrs, properties, regions);
1935 auto field = adaptor.getFieldAttr();
1940 auto resultType = structType.getFieldType(field);
1944 results.push_back(hw::InOutType::get(resultType));
1952LogicalResult AliasOp::verify() {
1954 if (getAliases().size() < 2)
1955 return emitOpError(
"alias must have at least two operands");
1968 for (
auto &op : llvm::reverse(body->getOperations())) {
1969 if (
auto instance = dyn_cast<Op>(op)) {
1970 if (
auto innerSym = instance.getInnerSym())
1971 if (innerSym->getSymName() == name)
1975 if (
auto ifdef = dyn_cast<IfDefOp>(op)) {
1977 findInstanceSymbolInBlock<Op>(name, ifdef.getThenBlock()))
1979 if (ifdef.hasElse())
1981 findInstanceSymbolInBlock<Op>(name, ifdef.getElseBlock()))
1992 return cast<hw::InstanceOp>(result.getOp());
1996 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1997 if (!topLevelModuleOp)
2000 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2001 topLevelModuleOp.lookupSymbol(getInstance().getModule()));
2006 return findInstanceSymbolInBlock<hw::InstanceOp>(getInstance().
getName(),
2007 hwModule.getBodyBlock());
2011LogicalResult BindOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2012 auto module = (*this)->getParentOfType<mlir::ModuleOp>();
2013 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2014 symbolTable.lookupSymbolIn(module, getInstance().getModule()));
2016 return emitError(
"Referenced module doesn't exist ")
2017 << getInstance().getModule() <<
"::" << getInstance().getName();
2019 auto inst = findInstanceSymbolInBlock<hw::InstanceOp>(
2020 getInstance().
getName(), hwModule.getBodyBlock());
2022 return emitError(
"Referenced instance doesn't exist ")
2023 << getInstance().getModule() <<
"::" << getInstance().getName();
2024 if (!inst.getDoNotPrint())
2025 return emitError(
"Referenced instance isn't marked as doNotPrint");
2029void BindOp::build(OpBuilder &builder, OperationState &odsState, StringAttr mod,
2031 auto ref = hw::InnerRefAttr::get(mod, name);
2032 odsState.addAttribute(
"instance", ref);
2039void SVVerbatimSourceOp::print(OpAsmPrinter &p) {
2042 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2043 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2044 p << visibility.getValue() <<
' ';
2046 p.printSymbolName(getSymName());
2052 SmallVector<StringRef> omittedAttrs = {SymbolTable::getSymbolAttrName(),
2053 "parameters", visibilityAttrName};
2055 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), omittedAttrs);
2058ParseResult SVVerbatimSourceOp::parse(OpAsmParser &parser,
2059 OperationState &result) {
2062 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2063 StringRef visibility;
2064 if (succeeded(parser.parseOptionalKeyword(&visibility,
2065 {
"public",
"private",
"nested"}))) {
2066 result.addAttribute(visibilityAttrName,
2067 parser.getBuilder().getStringAttr(visibility));
2071 StringAttr nameAttr;
2072 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2077 ArrayAttr parameters;
2080 result.addAttribute(
"parameters", parameters);
2083 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2089LogicalResult SVVerbatimSourceOp::verify() {
2091 if (getContent().
empty())
2092 return emitOpError(
"missing or empty content attribute");
2098SVVerbatimSourceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2100 if (
auto additionalFiles = getAdditionalFiles()) {
2101 for (
auto fileRef : *additionalFiles) {
2102 auto flatRef = dyn_cast<FlatSymbolRefAttr>(fileRef);
2105 "additional_files must contain flat symbol references");
2107 auto *referencedOp =
2108 symbolTable.lookupNearestSymbolFrom(getOperation(), flatRef);
2110 return emitOpError(
"references nonexistent file ")
2111 << flatRef.getValue();
2114 if (referencedOp->getName().getStringRef() !=
"emit.file")
2115 return emitOpError(
"references ")
2116 << flatRef.getValue() <<
", which is not an emit.file";
2127SmallVector<hw::PortInfo> SVVerbatimModuleOp::getPortList() {
2128 SmallVector<hw::PortInfo> ports;
2130 auto portLocs = getPortLocs();
2131 auto portAttrs = getPerPortAttrs();
2133 for (
size_t i = 0, e = moduleType.getNumPorts(); i < e; ++i) {
2134 auto port = moduleType.getPorts()[i];
2135 LocationAttr loc = portLocs && i < portLocs->size()
2136 ? cast<LocationAttr>((*portLocs)[i])
2137 : UnknownLoc::
get(getContext());
2138 DictionaryAttr attrs = portAttrs && i < portAttrs->size()
2139 ? cast<DictionaryAttr>((*portAttrs)[i])
2140 : DictionaryAttr::
get(getContext());
2147 ports.push_back({{port.name, port.type, dir}, i, attrs, loc});
2156size_t SVVerbatimModuleOp::getPortIdForInputId(
size_t idx) {
2160size_t SVVerbatimModuleOp::getPortIdForOutputId(
size_t idx) {
2164size_t SVVerbatimModuleOp::getNumPorts() {
2168size_t SVVerbatimModuleOp::getNumInputPorts() {
2172size_t SVVerbatimModuleOp::getNumOutputPorts() {
2176hw::ModuleType SVVerbatimModuleOp::getHWModuleType() {
return getModuleType(); }
2178ArrayRef<Attribute> SVVerbatimModuleOp::getAllPortAttrs() {
2179 if (
auto attrs = getPerPortAttrs())
2180 return attrs->getValue();
2184void SVVerbatimModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
2185 setPerPortAttrsAttr(ArrayAttr::get(getContext(), attrs));
2188void SVVerbatimModuleOp::removeAllPortAttrs() { removePerPortAttrsAttr(); }
2190SmallVector<Location> SVVerbatimModuleOp::getAllPortLocs() {
2191 if (
auto locs = getPortLocs()) {
2192 SmallVector<Location> result;
2193 result.reserve(locs->size());
2194 for (
auto loc : *locs)
2195 result.push_back(cast<Location>(loc));
2198 return SmallVector<Location>(
getNumPorts(), UnknownLoc::get(getContext()));
2201void SVVerbatimModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
2202 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
2205void SVVerbatimModuleOp::setHWModuleType(hw::ModuleType type) {
2206 setModuleTypeAttr(TypeAttr::get(type));
2209void SVVerbatimModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
2212 SmallVector<hw::ModulePort> ports;
2213 for (
size_t i = 0, e = currentType.getNumPorts(); i < e; ++i) {
2214 auto port = currentType.getPorts()[i];
2215 if (i < names.size())
2216 port.name = cast<StringAttr>(names[i]);
2217 ports.push_back(port);
2222void SVVerbatimModuleOp::print(OpAsmPrinter &p) {
2225 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2226 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2227 p << visibility.getValue() <<
' ';
2229 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
2237 SmallVector<StringRef> omittedAttrs = {
2238 SymbolTable::getSymbolAttrName(), SymbolTable::getVisibilityAttrName(),
2239 getModuleTypeAttrName().getValue(), getPerPortAttrsAttrName().getValue(),
2240 getPortLocsAttrName().getValue(), getParametersAttrName().getValue()};
2242 mlir::function_interface_impl::printFunctionAttributes(p, *
this,
2246ParseResult SVVerbatimModuleOp::parse(OpAsmParser &parser,
2247 OperationState &result) {
2248 using namespace mlir::function_interface_impl;
2249 auto builder = parser.getBuilder();
2252 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2255 StringAttr nameAttr;
2256 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2261 ArrayAttr parameters;
2265 SmallVector<hw::module_like_impl::PortParse> ports;
2271 result.addAttribute(getModuleTypeAttrName(result.name), modType);
2272 result.addAttribute(
"parameters", parameters);
2276 auto unknownLoc = builder.getUnknownLoc();
2277 SmallVector<Attribute> attrs, locs;
2279 for (
auto &port : ports) {
2280 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2281 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2282 locs.push_back(loc);
2286 result.addAttribute(
"per_port_attrs", builder.getArrayAttr(attrs));
2288 result.addAttribute(
"port_locs", builder.getArrayAttr(locs));
2290 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2294 if (!result.attributes.get(
"source"))
2295 return parser.emitError(parser.getCurrentLocation(),
2296 "sv.verbatim.module requires 'source' attribute");
2301LogicalResult SVVerbatimModuleOp::verify() {
return success(); }
2304SVVerbatimModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2306 auto sourceOp = dyn_cast_or_null<SVVerbatimSourceOp>(
2307 symbolTable.lookupNearestSymbolFrom(*
this, getSourceAttr()));
2309 return emitError(
"references ") << getSourceAttr().getAttr().getValue()
2310 <<
", which is not an sv.verbatim.source";
2319sv::InterfaceInstanceOp
2324 return cast<sv::InterfaceInstanceOp>(result.getOp());
2328 auto *symbolTable = SymbolTable::getNearestSymbolTable(*
this);
2337 return findInstanceSymbolInBlock<sv::InterfaceInstanceOp>(
2338 getInstance().
getName(), &parentOp->getRegion(0).front());
2343BindInterfaceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2345 symbolTable.lookupNearestSymbolFrom(*
this, getInstance().getModule());
2347 return emitError(
"Referenced module doesn't exist ")
2348 << getInstance().getModule() <<
"::" << getInstance().getName();
2350 auto inst = findInstanceSymbolInBlock<sv::InterfaceInstanceOp>(
2351 getInstance().
getName(), &parentOp->getRegion(0).front());
2353 return emitError(
"Referenced interface doesn't exist ")
2354 << getInstance().getModule() <<
"::" << getInstance().getName();
2355 if (!inst.getDoNotPrint())
2356 return emitError(
"Referenced interface isn't marked as doNotPrint");
2365 StringAttr &terminalAttr) {
2366 SmallVector<Attribute> strings;
2367 ParseResult ret = parser.parseCommaSeparatedList([&]() {
2370 if (succeeded(parser.parseOptionalKeyword(&keyword))) {
2371 strings.push_back(parser.getBuilder().getStringAttr(keyword));
2374 if (succeeded(parser.parseAttribute(
2375 result, parser.getBuilder().getType<NoneType>()))) {
2376 strings.push_back(result);
2381 if (succeeded(ret)) {
2382 pathAttr = parser.getBuilder().getArrayAttr(
2383 ArrayRef<Attribute>(strings).drop_back());
2384 terminalAttr = cast<StringAttr>(*strings.rbegin());
2390 StringAttr terminalAttr) {
2391 llvm::interleaveComma(pathAttr, p);
2392 p <<
", " << terminalAttr;
2396LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2397 auto *table = SymbolTable::getNearestSymbolTable(*
this);
2398 auto path = dyn_cast_or_null<hw::HierPathOp>(
2399 symbolTable.lookupSymbolIn(table, getRefAttr()));
2401 return emitError(
"Referenced path doesn't exist ") << getRefAttr();
2408 if (
auto *result = cache->
getDefinition(getRefAttr().getAttr()))
2409 return cast<hw::HierPathOp>(result);
2411 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
2412 return topLevelModuleOp.lookupSymbol<hw::HierPathOp>(getRefAttr().getValue());
2420 PatternRewriter &rewriter,
2423 if (constant.getValue().isZero() == eraseIfZero) {
2424 rewriter.eraseOp(op);
2431template <
class Op,
bool EraseIfZero = false>
2433 PatternRewriter &rewriter) {
2437void AssertOp::getCanonicalizationPatterns(RewritePatternSet &results,
2439 results.add(canonicalizeImmediateVerifOp<AssertOp>);
2442void AssumeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2444 results.add(canonicalizeImmediateVerifOp<AssumeOp>);
2447void CoverOp::getCanonicalizationPatterns(RewritePatternSet &results,
2449 results.add(canonicalizeImmediateVerifOp<CoverOp, /* EraseIfZero = */ true>);
2452template <
class Op,
bool EraseIfZero = false>
2454 PatternRewriter &rewriter) {
2458void AssertConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2460 results.add(canonicalizeConcurrentVerifOp<AssertConcurrentOp>);
2463void AssumeConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2465 results.add(canonicalizeConcurrentVerifOp<AssumeConcurrentOp>);
2468void CoverConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2471 canonicalizeConcurrentVerifOp<CoverConcurrentOp, /* EraseIfZero */ true>);
2481 ArrayAttr &caseNamesArray,
2482 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
2484 SmallVector<Attribute> names;
2485 while (!p.parseOptionalKeyword(
"case")) {
2488 std::unique_ptr<Region> region = std::make_unique<Region>();
2489 if (p.parseLParen() || p.parseAttribute(
pattern) || p.parseComma() ||
2490 p.parseAttribute(name) || p.parseRParen() || p.parseRegion(*region))
2493 names.push_back(name);
2494 if (region->empty())
2495 region->push_back(
new Block());
2496 caseRegions.push_back(std::move(region));
2498 patternsArray = p.getBuilder().getArrayAttr(
patterns);
2499 caseNamesArray = p.getBuilder().getArrayAttr(names);
2506 ArrayAttr namesArray,
2507 MutableArrayRef<Region> caseRegions) {
2508 assert(patternsArray.size() == caseRegions.size());
2509 assert(patternsArray.size() == namesArray.size());
2510 for (
size_t i = 0, e = caseRegions.size(); i < e; ++i) {
2512 p <<
"case (" << patternsArray[i] <<
", " << namesArray[i] <<
") ";
2513 p.printRegion(caseRegions[i]);
2518LogicalResult GenerateCaseOp::verify() {
2519 size_t numPatterns = getCasePatterns().size();
2520 if (getCaseRegions().size() != numPatterns ||
2521 getCaseNames().size() != numPatterns)
2523 "Size of caseRegions, patterns, and caseNames must match");
2525 StringSet<> usedNames;
2526 for (Attribute name : getCaseNames()) {
2527 StringAttr nameStr = dyn_cast<StringAttr>(name);
2529 return emitOpError(
"caseNames must all be string attributes");
2530 if (usedNames.contains(nameStr.getValue()))
2531 return emitOpError(
"caseNames must be unique");
2532 usedNames.insert(nameStr.getValue());
2540ModportStructAttr ModportStructAttr::get(MLIRContext *
context,
2541 ModportDirection direction,
2542 FlatSymbolRefAttr signal) {
2550ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
2551 auto builder = parser.getBuilder();
2553 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2556 StringAttr nameAttr;
2557 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2561 SmallVector<hw::module_like_impl::PortParse> ports;
2567 result.addAttribute(FuncOp::getModuleTypeAttrName(result.name), modType);
2571 auto unknownLoc = builder.getUnknownLoc();
2572 SmallVector<Attribute> attrs, inputLocs, outputLocs;
2573 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
2574 return attr && cast<Location>(attr) != unknownLoc;
2577 for (
auto &port : ports) {
2578 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2579 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2584 result.addAttribute(FuncOp::getPerArgumentAttrsAttrName(result.name),
2585 builder.getArrayAttr(attrs));
2587 if (llvm::any_of(outputLocs, nonEmptyLocsFn))
2588 result.addAttribute(FuncOp::getResultLocsAttrName(result.name),
2589 builder.getArrayAttr(outputLocs));
2591 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2595 SmallVector<OpAsmParser::Argument, 4> entryArgs;
2596 for (
auto &port : ports)
2598 entryArgs.push_back(port);
2602 auto *body = result.addRegion();
2603 llvm::SMLoc loc = parser.getCurrentLocation();
2605 mlir::OptionalParseResult parseResult =
2606 parser.parseOptionalRegion(*body, entryArgs,
2608 if (parseResult.has_value()) {
2609 if (failed(*parseResult))
2613 return parser.emitError(loc,
"expected non-empty function body");
2615 if (llvm::any_of(inputLocs, nonEmptyLocsFn))
2616 result.addAttribute(FuncOp::getInputLocsAttrName(result.name),
2617 builder.getArrayAttr(inputLocs));
2623void FuncOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2628 auto func = cast<FuncOp>(region.getParentOp());
2630 auto *block = ®ion.front();
2632 auto names = func.getModuleType().getInputNames();
2633 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
2635 setNameFn(block->getArgument(i), cast<StringAttr>(names[i]));
2639Type FuncOp::getExplicitlyReturnedType() {
2640 if (!getPerArgumentAttrs() || getNumOutputs() == 0)
2645 auto lastArgumentAttr = dyn_cast<DictionaryAttr>(
2646 getPerArgumentAttrsAttr()[getPerArgumentAttrsAttr().size() - 1]);
2649 lastArgumentAttr.getAs<UnitAttr>(getExplicitlyReturnedAttrName()))
2650 return lastArgument.type;
2654ArrayRef<Attribute> FuncOp::getAllPortAttrs() {
2655 if (getPerArgumentAttrs())
2656 return getPerArgumentAttrs()->getValue();
2660void FuncOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
2661 setPerArgumentAttrsAttr(ArrayAttr::get(getContext(), attrs));
2664void FuncOp::removeAllPortAttrs() { setPerArgumentAttrsAttr({}); }
2665SmallVector<Location> FuncOp::getAllPortLocs() {
2666 SmallVector<Location> portLocs;
2668 auto resultLocs = getResultLocsAttr();
2669 unsigned inputCount = 0;
2671 auto unknownLoc = UnknownLoc::get(getContext());
2673 auto inputLocs = getInputLocsAttr();
2674 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2675 if (modType.isOutput(i)) {
2676 auto loc = resultLocs
2678 resultLocs.getValue()[portLocs.size() - inputCount])
2680 portLocs.push_back(loc);
2682 auto loc = body ? body->getArgument(inputCount).getLoc()
2683 : (inputLocs ? cast<Location>(inputLocs[inputCount])
2685 portLocs.push_back(loc);
2692void FuncOp::setAllPortLocsAttrs(llvm::ArrayRef<mlir::Attribute> locs) {
2693 SmallVector<Attribute> resultLocs, inputLocs;
2694 unsigned inputCount = 0;
2697 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2698 if (modType.isOutput(i))
2699 resultLocs.push_back(locs[i]);
2701 body->getArgument(inputCount++).setLoc(cast<Location>(locs[i]));
2703 inputLocs.push_back(locs[i]);
2705 setResultLocsAttr(ArrayAttr::get(getContext(), resultLocs));
2707 setInputLocsAttr(ArrayAttr::get(getContext(), inputLocs));
2710SmallVector<hw::PortInfo> FuncOp::getPortList() {
return getPortList(
false); }
2713 auto modTy = getHWModuleType();
2714 auto emptyDict = DictionaryAttr::get(getContext());
2715 LocationAttr loc = getPortLoc(idx);
2716 DictionaryAttr attrs = dyn_cast_or_null<DictionaryAttr>(getPortAttrs(idx));
2719 return {modTy.getPorts()[idx],
2720 modTy.isOutput(idx) ? modTy.getOutputIdForPortId(idx)
2721 : modTy.getInputIdForPortId(idx),
2725SmallVector<hw::PortInfo> FuncOp::getPortList(
bool excludeExplicitReturn) {
2727 auto emptyDict = DictionaryAttr::get(getContext());
2728 auto skipLastArgument = getExplicitlyReturnedType() && excludeExplicitReturn;
2729 SmallVector<hw::PortInfo> retval;
2731 for (
unsigned i = 0, e = skipLastArgument ? modTy.getNumPorts() - 1
2734 DictionaryAttr attrs = emptyDict;
2735 if (
auto perArgumentAttr = getPerArgumentAttrs())
2736 if (
auto argumentAttr =
2737 dyn_cast_or_null<DictionaryAttr>((*perArgumentAttr)[i]))
2738 attrs = argumentAttr;
2740 retval.push_back({modTy.getPorts()[i],
2741 modTy.isOutput(i) ? modTy.getOutputIdForPortId(i)
2742 : modTy.getInputIdForPortId(i),
2743 attrs, portAttr[i]});
2748void FuncOp::print(OpAsmPrinter &p) {
2752 op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
2756 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2757 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2758 p << visibility.getValue() <<
' ';
2759 p.printSymbolName(funcName);
2761 p, op.getBody(), op.getModuleType(),
2762 op.getPerArgumentAttrsAttr()
2763 ? ArrayRef<Attribute>(op.getPerArgumentAttrsAttr().getValue())
2764 : ArrayRef<Attribute>{},
2767 mlir::function_interface_impl::printFunctionAttributes(
2769 {visibilityAttrName, getModuleTypeAttrName(),
2770 getPerArgumentAttrsAttrName(), getInputLocsAttrName(),
2771 getResultLocsAttrName()});
2773 Region &body = op->getRegion(0);
2774 if (!body.empty()) {
2776 p.printRegion(body,
false,
2785LogicalResult ReturnOp::verify() {
2786 auto func = getParentOp<sv::FuncOp>();
2787 auto funcResults = func.getResultTypes();
2788 auto returnedValues = getOperands();
2789 if (funcResults.size() != returnedValues.size())
2790 return emitOpError(
"must have same number of operands as region results.");
2792 for (
size_t i = 0, e = funcResults.size(); i < e; ++i) {
2793 if (funcResults[i] != returnedValues[i].getType()) {
2794 emitOpError(
"output types must match function. In "
2796 << i <<
", expected " << funcResults[i] <<
", but got "
2797 << returnedValues[i].getType() <<
".";
2810 mlir::Operation::result_range results) {
2811 if (!op.getExplicitlyReturnedType())
2813 return results.back();
2816Value FuncCallOp::getExplicitlyReturnedValue(sv::FuncOp op) {
2820Value FuncCallProceduralOp::getExplicitlyReturnedValue(sv::FuncOp op) {
2825FuncCallProceduralOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2826 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
2827 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
2829 return emitError(
"cannot find function declaration '")
2830 << getCallee() <<
"'";
2834LogicalResult FuncCallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2835 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
2836 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
2838 return emitError(
"cannot find function declaration '")
2839 << getCallee() <<
"'";
2842 if (referencedOp.getNumOutputs() != 1 ||
2843 !referencedOp.getExplicitlyReturnedType()) {
2844 auto diag = emitError()
2845 <<
"function called in a non-procedural region must "
2846 "return a single result";
2847 diag.attachNote(referencedOp.getLoc()) <<
"doesn't satisfy the constraint";
2858FuncDPIImportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2859 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
2860 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
2863 return emitError(
"cannot find function declaration '")
2864 << getCallee() <<
"'";
2865 if (!referencedOp.isDeclaration())
2866 return emitError(
"imported function must be a declaration but '")
2867 << getCallee() <<
"' is defined";
2878static LogicalResult
verify(Value clock,
bool eventExists, mlir::Location loc) {
2879 if ((!clock && eventExists) || (clock && !eventExists))
2880 return mlir::emitError(
2881 loc,
"Every clock must be associated to an even and vice-versa!");
2886LogicalResult AssertPropertyOp::verify() {
2891LogicalResult AssumePropertyOp::verify() {
2896LogicalResult CoverPropertyOp::verify() {
2906#define GET_OP_CLASSES
2907#include "circt/Dialect/SV/SV.cpp.inc"
assert(baseType &&"element must be base type")
static bool hasSVAttributes(Operation *op)
static std::unique_ptr< Context > context
static LogicalResult canonicalizeImmediateVerifOp(Op op, PatternRewriter &rewriter)
static void replaceOpWithRegion(PatternRewriter &rewriter, Operation *op, Region ®ion)
Replaces the given op with the contents of the given single-block region.
static LogicalResult eraseIfZeroOrNotZero(Operation *op, Value predicate, Value enable, PatternRewriter &rewriter, bool eraseIfZero)
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
static SmallVector< Location > getAllPortLocs(ModTy module)
static void setHWModuleType(ModTy &mod, ModuleType type)
static Location getLoc(DefSlot slot)
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
RewritePatternSet pattern
bool parseCaseRegions(OpAsmParser &p, ArrayAttr &patternsArray, ArrayAttr &caseNamesArray, SmallVectorImpl< std::unique_ptr< Region > > &caseRegions)
Parse cases formatted like: case (pattern, "name") { ... }.
ParseResult parseIfaceTypeAndSignal(OpAsmParser &p, Type &ifaceTy, FlatSymbolRefAttr &signalName)
LogicalResult verifySignalExists(Value ifaceVal, FlatSymbolRefAttr signalName)
void printCaseRegions(OpAsmPrinter &p, Operation *, ArrayAttr patternsArray, ArrayAttr namesArray, MutableArrayRef< Region > caseRegions)
Print cases formatted like: case (pattern, "name") { ... }.
static Value getExplicitlyReturnedValueImpl(sv::FuncOp op, mlir::Operation::result_range results)
void printIfaceTypeAndSignal(OpAsmPrinter &p, Operation *op, Type type, FlatSymbolRefAttr signalName)
static void printModportStructs(OpAsmPrinter &p, Operation *, ArrayAttr portsAttr)
static LogicalResult canonicalizeConcurrentVerifOp(Op op, PatternRewriter &rewriter)
static ParseResult parseEventList(OpAsmParser &p, Attribute &eventsAttr, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &clocksOperands)
static MacroDeclOp getReferencedMacro(const hw::HWSymbolCache *cache, Operation *op, FlatSymbolRefAttr macroName)
static LogicalResult canonicalizeIfDefLike(Op op, PatternRewriter &rewriter)
static LogicalResult verifyVerbatimSymbols(Operation *op, ArrayAttr symbols, hw::InnerRefNamespace &ns)
Helper function to verify inner refs in symbols array for verbatim ops.
static LogicalResult verifyVerbatimFlatSymbolRefs(Operation *op, ArrayAttr symbols, SymbolTableCollection &symbolTable)
Helper function to verify flat symbol refs in symbols array for verbatim ops.
ParseResult parseXMRPath(::mlir::OpAsmParser &parser, ArrayAttr &pathAttr, StringAttr &terminalAttr)
static Type getElementTypeOfWidth(Type type, int32_t width)
static LogicalResult mergeNeiboringAssignments(AssignTy op, PatternRewriter &rewriter)
static Op findInstanceSymbolInBlock(StringAttr name, Block *body)
Instances must be at the top level of the hw.module (or within a `ifdef)
static void printEventList(OpAsmPrinter &p, AlwaysOp op, ArrayAttr portsAttr, OperandRange operands)
static SmallVector< CasePatternBit > getPatternBitsForValue(const APInt &value)
static ParseResult parseImplicitInitType(OpAsmParser &p, mlir::Type regType, std::optional< OpAsmParser::UnresolvedOperand > &initValue, mlir::Type &initType)
static LogicalResult verifyMacroIdentSymbolUses(Operation *op, FlatSymbolRefAttr attr, SymbolTableCollection &symbolTable)
Verifies symbols referenced by macro identifiers.
static void getVerbatimExprAsmResultNames(Operation *op, function_ref< void(Value, StringRef)> setNameFn)
Get the asm name for sv.verbatim.expr and sv.verbatim.expr.se.
static void printImplicitInitType(OpAsmPrinter &p, Operation *op, mlir::Type regType, mlir::Value initValue, mlir::Type initType)
static ParseResult parseModportStructs(OpAsmParser &parser, ArrayAttr &portsAttr)
static Operation * lookupSymbolInNested(Operation *symbolTableOp, StringRef symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
void printXMRPath(OpAsmPrinter &p, XMROp op, ArrayAttr pathAttr, StringAttr terminalAttr)
static InstancePath empty
This stores lookup tables to make manipulating and working with the IR more efficient.
HWSymbolCache::Item getInnerDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name) const
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
CasePatternBit getBit(size_t bitNumber) const
Return the specified bit, bit 0 is the least significant bit.
bool hasZ() const override
Return true if this pattern has an Z.
CaseBitPattern(ArrayRef< CasePatternBit > bits, MLIRContext *context)
Get a CasePattern from a specified list of CasePatternBit.
bool hasX() const override
Return true if this pattern has an X.
hw::EnumFieldAttr enumAttr
StringRef getFieldValue() const
create(array_value, low_index, ret_type)
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction
The direction of a Component or Cell port.
Value createOrFoldNot(OpBuilder &builder, Location loc, Value value, bool twoState=false)
Create a `‘Not’' gate on a value.
uint64_t getWidth(Type t)
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
void printModuleSignatureNew(OpAsmPrinter &p, Region &body, hw::ModuleType modType, ArrayRef< Attribute > portAttrs, ArrayRef< Location > locAttrs)
bool isHWIntegerType(mlir::Type type)
Return true if the specified type is a value HW Integer type.
bool isOffset(Value base, Value index, uint64_t offset)
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function type.
bool isHWEnumType(mlir::Type type)
Return true if the specified type is a HW Enum type.
mlir::Type getCanonicalType(mlir::Type type)
CasePatternBit
This describes the bit in a pattern, 0/1/x/z.
char getLetter(CasePatternBit bit)
Return the letter for the specified pattern bit, e.g. "0", "1", "x" or "z".
bool hasSVAttributes(mlir::Operation *op)
Helper functions to handle SV attributes.
void createNestedIfDefs(ArrayRef< StringAttr > macroSymbols, llvm::function_ref< void(StringAttr, std::function< void()>, std::function< void()>)> ifdefCtor, llvm::function_ref< void(size_t)> thenCtor, llvm::function_ref< void()> defaultCtor)
Create nested ifdef operations for a list of macro symbols.
bool is2StateExpression(Value v)
Returns if the expression is known to be 2-state (binary)
mlir::Type getInOutElementType(mlir::Type type)
Return the element type of an InOutType or null if the operand isn't an InOut type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ParseResult parseOptionalParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Parse an parameter list if present.
void printOptionalParameterList(OpAsmPrinter &p, Operation *op, ArrayAttr parameters)
Print a parameter list for a module or instance.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.