26#include "mlir/IR/Builders.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Matchers.h"
29#include "mlir/IR/PatternMatch.h"
30#include "mlir/Interfaces/FunctionImplementation.h"
31#include "llvm/ADT/SmallString.h"
32#include "llvm/ADT/StringExtras.h"
33#include "llvm/ADT/TypeSwitch.h"
44bool sv::is2StateExpression(Value v) {
45 if (
auto *op = v.getDefiningOp()) {
46 if (
auto attr = op->getAttrOfType<UnitAttr>(
"twoState"))
54bool sv::isExpression(Operation *op) {
55 return isa<VerbatimExprOp, VerbatimExprSEOp, GetModportOp,
56 ReadInterfaceSignalOp, ConstantXOp, ConstantZOp, ConstantStrOp,
57 MacroRefExprOp, MacroRefExprSEOp>(op);
65 Region ®ion = symbolTableOp->getRegion(0);
70 for (Block &block : region)
71 for (Operation &nestedOp : block) {
72 if (
auto symbolOp = dyn_cast<mlir::SymbolOpInterface>(&nestedOp);
73 symbolOp && symbolOp.getName() == symbol)
75 if (!nestedOp.hasTrait<OpTrait::SymbolTable>() &&
76 nestedOp.getNumRegions()) {
87 SymbolTableCollection &symbolTable) {
88 auto *refOp = symbolTable.lookupNearestSymbolFrom(op, attr);
90 return op->emitError(
"references an undefined symbol: ") << attr;
91 if (!isa<MacroDeclOp>(refOp))
92 return op->emitError(
"must reference a macro declaration");
100template <
typename Package>
102 for (Operation &op : *package.getBodyBlock())
103 if (!isa<hw::TypedeclOp>(op))
104 return package.emitOpError(
105 "body may only contain hw.typedecl operations");
109LogicalResult PackageOp::verify() {
return verifyPackage(*
this); }
111LogicalResult PackageExternOp::verify() {
112 if (
auto name = getVerilogNameAttr()) {
113 if (name.getValue().empty())
114 return emitOpError(
"'verilogName' must be a non-empty string");
115 }
else if (!isPublic()) {
116 return emitOpError(
"non-public packages require 'verilogName' to "
117 "preserve their external name when renamed");
130 for (
auto symbol : symbols) {
131 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(symbol)) {
133 return op->emitError() <<
"inner symbol reference " << innerRef
134 <<
" could not be found";
144 SymbolTableCollection &symbolTable) {
145 for (
auto symbol : symbols) {
146 if (
auto flatRef = dyn_cast<FlatSymbolRefAttr>(symbol)) {
147 auto *referencedOp = symbolTable.lookupNearestSymbolFrom(op, flatRef);
149 return op->emitOpError(
"references nonexistent symbol '")
150 << flatRef.getValue() <<
"'";
160LogicalResult VerbatimOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
172 function_ref<
void(Value, StringRef)> setNameFn) {
176 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
177 auto name = op->getAttrOfType<StringAttr>(
"format_string").getValue();
179 if (name.starts_with(
"`"))
180 name = name.drop_front();
181 name = name.take_while(isOkCharacter);
183 setNameFn(op->getResult(0), name);
186void VerbatimExprOp::getAsmResultNames(
187 function_ref<
void(Value, StringRef)> setNameFn) {
196VerbatimExprOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
201void VerbatimExprSEOp::getAsmResultNames(
202 function_ref<
void(Value, StringRef)> setNameFn) {
211VerbatimExprSEOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
220void MacroRefExprOp::getAsmResultNames(
221 function_ref<
void(Value, StringRef)> setNameFn) {
222 setNameFn(getResult(), getMacroName());
225void MacroRefExprSEOp::getAsmResultNames(
226 function_ref<
void(Value, StringRef)> setNameFn) {
227 setNameFn(getResult(), getMacroName());
232 FlatSymbolRefAttr macroName) {
234 if (
auto *result = cache->
getDefinition(macroName.getAttr()))
235 return cast<MacroDeclOp>(result);
237 auto topLevelModuleOp = op->getParentOfType<ModuleOp>();
238 return topLevelModuleOp.lookupSymbol<MacroDeclOp>(macroName.getValue());
244 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
249 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
256std::string MacroErrorOp::getMacroIdentifier() {
257 const auto *prefix =
"_ERROR";
258 auto msg = getMessage();
259 if (!msg || msg->empty())
262 std::string id(prefix);
264 for (
auto c : *msg) {
265 if (llvm::isAlnum(c))
278 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
282 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
287MacroRefExprOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
293MacroRefExprSEOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
298LogicalResult MacroDefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
303LogicalResult MacroRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
311StringRef MacroDeclOp::getMacroIdentifier() {
312 return getVerilogName().value_or(getSymName());
319void ConstantXOp::getAsmResultNames(
320 function_ref<
void(Value, StringRef)> setNameFn) {
321 SmallVector<char, 32> specialNameBuffer;
322 llvm::raw_svector_ostream specialName(specialNameBuffer);
324 setNameFn(getResult(), specialName.str());
327LogicalResult ConstantXOp::verify() {
330 return emitError(
"unsupported type");
334void ConstantZOp::getAsmResultNames(
335 function_ref<
void(Value, StringRef)> setNameFn) {
336 SmallVector<char, 32> specialNameBuffer;
337 llvm::raw_svector_ostream specialName(specialNameBuffer);
339 setNameFn(getResult(), specialName.str());
342LogicalResult ConstantZOp::verify() {
345 return emitError(
"unsupported type");
353LogicalResult ConcatStrOp::verify() {
355 if (getInputs().
empty())
356 return emitError(
"sv.concat_str requires at least one operand");
360OpFoldResult ConcatStrOp::fold(FoldAdaptor) {
361 if (getInputs().size() == 1)
362 return getInputs().front();
370void LocalParamOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
372 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
373 if (!nameAttr.getValue().empty())
374 setNameFn(getResult(), nameAttr.getValue());
377LogicalResult LocalParamOp::verify() {
379 return hw::checkParameterInContext(
388 OpAsmParser &p, Type varType,
389 std::optional<OpAsmParser::UnresolvedOperand> &initValue, Type &initType) {
390 if (!initValue.has_value())
393 auto var = dyn_cast<VarType>(varType);
395 return p.emitError(p.getCurrentLocation(),
396 "expected `!sv.var<T>` type for var");
398 initType = var.getElementType();
403 Type varType, Value initValue,
406void VarOp::build(OpBuilder &builder, OperationState &odsState,
407 Type
elementType, StringAttr name, hw::InnerSymAttr innerSym,
410 auto &props = odsState.getOrAddProperties<Properties>();
411 props.name = name ? name : builder.getStringAttr(
"");
413 props.inner_sym = innerSym;
416 odsState.addOperands(initValue);
421void VarOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
425 setNameFn(getResult(), name);
428std::optional<size_t> VarOp::getTargetResultIndex() {
return 0; }
436 std::optional<OpAsmParser::UnresolvedOperand> &initValue,
437 mlir::Type &initType) {
438 if (!initValue.has_value())
441 hw::InOutType ioType = dyn_cast<hw::InOutType>(regType);
443 return p.emitError(p.getCurrentLocation(),
"expected inout type for reg");
445 initType = ioType.getElementType();
450 mlir::Type regType, mlir::Value initValue,
451 mlir::Type initType) {}
453void RegOp::build(OpBuilder &builder, OperationState &odsState,
454 Type
elementType, StringAttr name, hw::InnerSymAttr innerSym,
455 mlir::Value initValue) {
457 name = builder.getStringAttr(
"");
458 odsState.addAttribute(
"name", name);
462 odsState.addTypes(hw::InOutType::get(
elementType));
464 odsState.addOperands(initValue);
469void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
471 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
472 if (!nameAttr.getValue().empty())
473 setNameFn(getResult(), nameAttr.getValue());
476std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
479LogicalResult RegOp::canonicalize(
RegOp op, PatternRewriter &rewriter) {
485 if (op.getInnerSymAttr())
489 for (
auto *user : op.getResult().getUsers())
494 for (
auto *user :
llvm::make_early_inc_range(op.getResult().getUsers()))
495 rewriter.eraseOp(user);
498 rewriter.eraseOp(op);
506void LogicOp::build(OpBuilder &builder, OperationState &odsState,
508 hw::InnerSymAttr innerSym) {
510 name = builder.getStringAttr(
"");
511 odsState.addAttribute(
"name", name);
515 odsState.addTypes(hw::InOutType::get(
elementType));
520void LogicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
522 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
523 if (!nameAttr.getValue().empty())
524 setNameFn(getResult(), nameAttr.getValue());
527std::optional<size_t> LogicOp::getTargetResultIndex() {
return 0; }
537void IfDefOp::build(OpBuilder &builder, OperationState &result, StringRef cond,
538 std::function<
void()> thenCtor,
539 std::function<
void()> elseCtor) {
540 build(builder, result, builder.getStringAttr(cond), std::move(thenCtor),
541 std::move(elseCtor));
544void IfDefOp::build(OpBuilder &builder, OperationState &result, StringAttr cond,
545 std::function<
void()> thenCtor,
546 std::function<
void()> elseCtor) {
547 build(builder, result, FlatSymbolRefAttr::get(builder.getContext(), cond),
548 std::move(thenCtor), std::move(elseCtor));
551void IfDefOp::build(OpBuilder &builder, OperationState &result,
552 FlatSymbolRefAttr cond, std::function<
void()> thenCtor,
553 std::function<
void()> elseCtor) {
554 build(builder, result, MacroIdentAttr::get(builder.getContext(), cond),
555 std::move(thenCtor), std::move(elseCtor));
558void IfDefOp::build(OpBuilder &builder, OperationState &result,
559 MacroIdentAttr cond, std::function<
void()> thenCtor,
560 std::function<
void()> elseCtor) {
561 OpBuilder::InsertionGuard guard(builder);
563 result.addAttribute(
"cond", cond);
564 builder.createBlock(result.addRegion());
570 Region *elseRegion = result.addRegion();
572 builder.createBlock(elseRegion);
577LogicalResult IfDefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
584 if (!op.getThenBlock()->empty())
587 if (op.hasElse() && !op.getElseBlock()->empty())
590 rewriter.eraseOp(op);
594LogicalResult IfDefOp::canonicalize(
IfDefOp op, PatternRewriter &rewriter) {
603 ArrayRef<StringAttr> macroSymbols,
604 llvm::function_ref<
void(StringAttr, std::function<
void()>,
605 std::function<
void()>)>
607 llvm::function_ref<
void(
size_t)> thenCtor,
608 llvm::function_ref<
void()> defaultCtor) {
611 std::function<void(
size_t)> buildNested = [&](
size_t index) {
612 if (index >= macroSymbols.size()) {
628 [&, index]() { buildNested(index + 1); });
638void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
639 StringRef cond, std::function<
void()> thenCtor,
640 std::function<
void()> elseCtor) {
641 build(builder, result, builder.getStringAttr(cond), std::move(thenCtor),
642 std::move(elseCtor));
645void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
646 StringAttr cond, std::function<
void()> thenCtor,
647 std::function<
void()> elseCtor) {
648 build(builder, result, FlatSymbolRefAttr::get(builder.getContext(), cond),
649 std::move(thenCtor), std::move(elseCtor));
652void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
653 FlatSymbolRefAttr cond,
654 std::function<
void()> thenCtor,
655 std::function<
void()> elseCtor) {
656 build(builder, result, MacroIdentAttr::get(builder.getContext(), cond),
657 std::move(thenCtor), std::move(elseCtor));
660void IfDefProceduralOp::build(OpBuilder &builder, OperationState &result,
662 std::function<
void()> thenCtor,
663 std::function<
void()> elseCtor) {
664 OpBuilder::InsertionGuard guard(builder);
666 result.addAttribute(
"cond", cond);
667 builder.createBlock(result.addRegion());
673 Region *elseRegion = result.addRegion();
675 builder.createBlock(elseRegion);
680LogicalResult IfDefProceduralOp::canonicalize(IfDefProceduralOp op,
681 PatternRewriter &rewriter) {
686IfDefProceduralOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
694void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
695 std::function<
void()> thenCtor,
696 std::function<
void()> elseCtor) {
697 OpBuilder::InsertionGuard guard(builder);
699 result.addOperands(cond);
700 builder.createBlock(result.addRegion());
706 Region *elseRegion = result.addRegion();
708 builder.createBlock(elseRegion);
716 assert(llvm::hasSingleElement(region) &&
"expected single-region block");
717 Block *fromBlock = ®ion.front();
719 op->getBlock()->getOperations().splice(Block::iterator(op),
720 fromBlock->getOperations());
723LogicalResult IfOp::canonicalize(IfOp op, PatternRewriter &rewriter) {
728 if (
auto constant = op.getCond().getDefiningOp<
hw::ConstantOp>()) {
730 if (constant.getValue().isAllOnes())
732 else if (!op.getElseRegion().empty())
735 rewriter.eraseOp(op);
741 if (!op.getThenBlock()->empty() && op.hasElse() &&
742 op.getElseBlock()->empty()) {
743 rewriter.eraseBlock(op.getElseBlock());
750 if (!op.getThenBlock()->empty())
754 if (!op.hasElse() || op.getElseBlock()->empty()) {
755 rewriter.eraseOp(op);
766 auto *thenBlock = op.getThenBlock(), *elseBlock = op.getElseBlock();
769 thenBlock->getOperations().splice(thenBlock->end(),
770 elseBlock->getOperations());
771 rewriter.eraseBlock(elseBlock);
781AlwaysOp::Condition AlwaysOp::getCondition(
size_t idx) {
782 return Condition{EventControl(cast<IntegerAttr>(getEvents()[idx]).
getInt()),
786void AlwaysOp::build(OpBuilder &builder, OperationState &result,
787 ArrayRef<sv::EventControl> events, ArrayRef<Value> clocks,
788 std::function<
void()> bodyCtor) {
789 assert(events.size() == clocks.size() &&
790 "mismatch between event and clock list");
791 OpBuilder::InsertionGuard guard(builder);
793 SmallVector<Attribute> eventAttrs;
794 for (
auto event : events)
795 eventAttrs.push_back(
796 builder.getI32IntegerAttr(static_cast<int32_t>(event)));
797 result.addAttribute(
"events", builder.getArrayAttr(eventAttrs));
798 result.addOperands(clocks);
801 builder.createBlock(result.addRegion());
809LogicalResult AlwaysOp::verify() {
810 if (getEvents().size() != getNumOperands())
811 return emitError(
"different number of operands and events");
816 OpAsmParser &p, Attribute &eventsAttr,
817 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &clocksOperands) {
820 SmallVector<Attribute> events;
822 auto loc = p.getCurrentLocation();
824 if (!p.parseOptionalKeyword(&keyword)) {
826 auto kind = sv::symbolizeEventControl(keyword);
827 if (!kind.has_value())
828 return p.emitError(loc,
"expected 'posedge', 'negedge', or 'edge'");
829 auto eventEnum =
static_cast<int32_t
>(*kind);
830 events.push_back(p.getBuilder().getI32IntegerAttr(eventEnum));
832 clocksOperands.push_back({});
833 if (p.parseOperand(clocksOperands.back()))
836 if (failed(p.parseOptionalComma()))
838 if (p.parseKeyword(&keyword))
842 eventsAttr = p.getBuilder().getArrayAttr(events);
847 OperandRange operands) {
848 for (
size_t i = 0, e = op.getNumConditions(); i != e; ++i) {
851 auto cond = op.getCondition(i);
852 p << stringifyEventControl(cond.event);
854 p.printOperand(cond.value);
862void AlwaysFFOp::build(OpBuilder &builder, OperationState &result,
863 EventControl clockEdge, Value clock,
864 std::function<
void()> bodyCtor) {
865 OpBuilder::InsertionGuard guard(builder);
868 "clockEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(clockEdge)));
869 result.addOperands(clock);
872 builder.getI32IntegerAttr(
static_cast<int32_t
>(ResetType::NoReset)));
875 builder.createBlock(result.addRegion());
884void AlwaysFFOp::build(OpBuilder &builder, OperationState &result,
885 EventControl clockEdge, Value clock,
886 ResetType resetStyle, EventControl resetEdge,
887 Value reset, std::function<
void()> bodyCtor,
888 std::function<
void()> resetCtor) {
889 OpBuilder::InsertionGuard guard(builder);
892 "clockEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(clockEdge)));
893 result.addOperands(clock);
894 result.addAttribute(
"resetStyle", builder.getI32IntegerAttr(
895 static_cast<int32_t
>(resetStyle)));
897 "resetEdge", builder.getI32IntegerAttr(
static_cast<int32_t
>(resetEdge)));
898 result.addOperands(reset);
901 builder.createBlock(result.addRegion());
907 builder.createBlock(result.addRegion());
917void AlwaysCombOp::build(OpBuilder &builder, OperationState &result,
918 std::function<
void()> bodyCtor) {
919 OpBuilder::InsertionGuard guard(builder);
921 builder.createBlock(result.addRegion());
931void InitialOp::build(OpBuilder &builder, OperationState &result,
932 std::function<
void()> bodyCtor) {
933 OpBuilder::InsertionGuard guard(builder);
935 builder.createBlock(result.addRegion());
958 llvm_unreachable(
"invalid casez PatternBit");
963 return CasePatternBit(
unsigned(intAttr.getValue()[bitNumber * 2]) +
964 2 *
unsigned(intAttr.getValue()[bitNumber * 2 + 1]));
968 for (
size_t i = 0, e = getWidth(); i != e; ++i)
975 for (
size_t i = 0, e = getWidth(); i != e; ++i)
981 SmallVector<CasePatternBit> result;
982 result.reserve(value.getBitWidth());
983 for (
size_t i = 0, e = value.getBitWidth(); i != e; ++i)
1001 APInt
pattern(bits.size() * 2, 0);
1002 for (
auto elt : llvm::reverse(bits)) {
1006 auto patternType = IntegerType::get(
context, bits.size() * 2);
1010auto CaseOp::getCases() -> SmallVector<CaseInfo, 4> {
1011 SmallVector<CaseInfo, 4> result;
1012 assert(getCasePatterns().size() == getNumRegions() &&
1013 "case pattern / region count mismatch");
1014 size_t nextRegion = 0;
1015 for (
auto elt : getCasePatterns()) {
1016 llvm::TypeSwitch<Attribute>(elt)
1017 .Case<hw::EnumFieldAttr>([&](
auto enumAttr) {
1018 result.push_back({std::make_unique<CaseEnumPattern>(enumAttr),
1019 &getRegion(nextRegion++).front()});
1021 .Case<CaseExprPatternAttr>([&](
auto exprAttr) {
1022 result.push_back({std::make_unique<CaseExprPattern>(getContext()),
1023 &getRegion(nextRegion++).front()});
1025 .Case<IntegerAttr>([&](
auto intAttr) {
1026 result.push_back({std::make_unique<CaseBitPattern>(intAttr),
1027 &getRegion(nextRegion++).front()});
1029 .Case<CaseDefaultPattern::AttrType>([&](
auto) {
1030 result.push_back({std::make_unique<CaseDefaultPattern>(getContext()),
1031 &getRegion(nextRegion++).front()});
1034 assert(
false &&
"invalid case pattern attribute type");
1042 return cast<hw::EnumFieldAttr>(
enumAttr).getField();
1052ParseResult CaseOp::parse(OpAsmParser &parser, OperationState &result) {
1053 auto &builder = parser.getBuilder();
1055 OpAsmParser::UnresolvedOperand condOperand;
1058 auto loc = parser.getCurrentLocation();
1061 if (!parser.parseOptionalKeyword(&keyword, {
"case",
"casex",
"casez"})) {
1062 auto kind = symbolizeCaseStmtType(keyword);
1063 auto caseEnum =
static_cast<int32_t
>(kind.value());
1064 result.addAttribute(
"caseStyle", builder.getI32IntegerAttr(caseEnum));
1068 if (!parser.parseOptionalKeyword(
1069 &keyword, {
"plain",
"priority",
"unique",
"unique0"})) {
1070 auto kind = symbolizeValidationQualifierTypeEnum(keyword);
1071 result.addAttribute(
"validationQualifier",
1072 ValidationQualifierTypeEnumAttr::get(
1073 builder.getContext(), kind.value()));
1076 if (parser.parseOperand(condOperand) || parser.parseColonType(condType) ||
1077 parser.parseOptionalAttrDict(result.attributes) ||
1078 parser.resolveOperand(condOperand, condType, result.operands))
1083 hw::EnumType enumType = dyn_cast<hw::EnumType>(canonicalCondType);
1084 unsigned condWidth = 0;
1086 if (!result.operands[0].getType().isSignlessInteger())
1087 return parser.emitError(loc,
"condition must have signless integer type");
1088 condWidth = condType.getIntOrFloatBitWidth();
1092 SmallVector<Attribute> casePatterns;
1093 SmallVector<CasePatternBit, 16> caseBits;
1095 mlir::OptionalParseResult caseValueParseResult;
1096 OpAsmParser::UnresolvedOperand caseValueOperand;
1097 if (succeeded(parser.parseOptionalKeyword(
"default"))) {
1098 casePatterns.push_back(CaseDefaultPattern(parser.getContext()).attr());
1099 }
else if (failed(parser.parseOptionalKeyword(
"case"))) {
1102 }
else if (enumType) {
1106 if (parser.parseKeyword(&caseVal))
1109 if (!enumType.contains(caseVal))
1110 return parser.emitError(loc)
1111 <<
"case value '" + caseVal +
"' is not a member of enum type "
1113 casePatterns.push_back(
1114 hw::EnumFieldAttr::get(parser.getEncodedSourceLoc(loc),
1115 builder.getStringAttr(caseVal), condType));
1116 }
else if ((caseValueParseResult =
1117 parser.parseOptionalOperand(caseValueOperand))
1119 if (failed(caseValueParseResult.value()) ||
1120 parser.resolveOperand(caseValueOperand, condType, result.operands))
1122 casePatterns.push_back(CaseExprPattern(parser.getContext()).attr());
1127 loc = parser.getCurrentLocation();
1128 if (parser.parseKeyword(&caseVal))
1131 if (caseVal.front() !=
'b')
1132 return parser.emitError(loc,
"expected case value starting with 'b'");
1133 caseVal = caseVal.drop_front();
1136 for (; !caseVal.empty(); caseVal = caseVal.drop_front()) {
1138 switch (caseVal.front()) {
1152 return parser.emitError(loc,
"unexpected case bit '")
1153 << caseVal.front() <<
"'";
1155 caseBits.push_back(bit);
1158 if (caseVal.size() > condWidth)
1159 return parser.emitError(loc,
"too many bits specified in pattern");
1160 std::reverse(caseBits.begin(), caseBits.end());
1163 if (caseBits.size() < condWidth)
1166 auto resultPattern = CaseBitPattern(caseBits, builder.getContext());
1167 casePatterns.push_back(resultPattern.attr());
1172 auto caseRegion = std::make_unique<Region>();
1173 if (parser.parseColon() || parser.parseRegion(*caseRegion))
1175 result.addRegion(std::move(caseRegion));
1178 result.addAttribute(
"casePatterns", builder.getArrayAttr(casePatterns));
1182void CaseOp::print(OpAsmPrinter &p) {
1184 if (getCaseStyle() == CaseStmtType::CaseXStmt)
1186 else if (getCaseStyle() == CaseStmtType::CaseZStmt)
1189 if (getValidationQualifier() !=
1190 ValidationQualifierTypeEnum::ValidationQualifierPlain)
1191 p << stringifyValidationQualifierTypeEnum(getValidationQualifier()) <<
' ';
1193 p << getCond() <<
" : " << getCond().getType();
1194 p.printOptionalAttrDict(
1195 (*this)->getAttrs(),
1196 {
"casePatterns",
"caseStyle",
"validationQualifier"});
1198 size_t caseValueIndex = 0;
1199 for (
auto &caseInfo : getCases()) {
1201 auto &
pattern = caseInfo.pattern;
1203 llvm::TypeSwitch<CasePattern *>(
pattern.get())
1204 .Case<CaseBitPattern>([&](
auto bitPattern) {
1206 for (
size_t bit = 0, e = bitPattern->getWidth(); bit != e; ++bit)
1207 p <<
getLetter(bitPattern->getBit(e - bit - 1));
1209 .Case<CaseEnumPattern>([&](
auto enumPattern) {
1210 p <<
"case " << enumPattern->getFieldValue();
1212 .Case<CaseExprPattern>([&](
auto) {
1214 p.printOperand(getCaseValues()[caseValueIndex++]);
1216 .Case<CaseDefaultPattern>([&](
auto) { p <<
"default"; })
1217 .Default([&](
auto) {
assert(
false &&
"unhandled case pattern"); });
1220 p.printRegion(*caseInfo.block->getParent(),
false,
1225LogicalResult CaseOp::verify() {
1228 return emitError(
"condition must have either integer or enum type");
1231 if (getCasePatterns().size() != getNumRegions())
1232 return emitOpError(
"case pattern / region count mismatch");
1239 OpBuilder &builder, OperationState &result, CaseStmtType caseStyle,
1240 ValidationQualifierTypeEnum validationQualifier, Value cond,
1242 std::function<std::unique_ptr<CasePattern>(
size_t)> caseCtor) {
1243 result.addOperands(cond);
1244 result.addAttribute(
"caseStyle",
1245 CaseStmtTypeAttr::get(builder.getContext(), caseStyle));
1246 result.addAttribute(
"validationQualifier",
1247 ValidationQualifierTypeEnumAttr::get(
1248 builder.getContext(), validationQualifier));
1249 SmallVector<Attribute> casePatterns;
1251 OpBuilder::InsertionGuard guard(builder);
1254 for (
size_t i = 0, e = numCases; i != e; ++i) {
1255 builder.createBlock(result.addRegion());
1256 casePatterns.push_back(caseCtor(i)->attr());
1259 result.addAttribute(
"casePatterns", builder.getArrayAttr(casePatterns));
1263LogicalResult CaseOp::canonicalize(CaseOp op, PatternRewriter &rewriter) {
1264 if (op.getCaseStyle() == CaseStmtType::CaseStmt)
1266 if (isa<hw::EnumType>(op.getCond().getType()))
1269 auto caseInfo = op.getCases();
1270 bool noXZ = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1271 return !ci.pattern.get()->hasX() && !ci.pattern.get()->hasZ();
1273 bool noX = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1274 if (isa<CaseDefaultPattern>(ci.pattern))
1276 return !ci.pattern.get()->hasX();
1278 bool noZ = llvm::all_of(caseInfo, [](
const CaseInfo &ci) {
1279 if (isa<CaseDefaultPattern>(ci.pattern))
1281 return !ci.pattern.get()->hasZ();
1284 if (op.getCaseStyle() == CaseStmtType::CaseXStmt) {
1286 rewriter.modifyOpInPlace(op, [&]() {
1287 op.setCaseStyleAttr(
1288 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseStmt));
1293 rewriter.modifyOpInPlace(op, [&]() {
1294 op.setCaseStyleAttr(
1295 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseZStmt));
1301 if (op.getCaseStyle() == CaseStmtType::CaseZStmt && noZ) {
1302 rewriter.modifyOpInPlace(op, [&]() {
1303 op.setCaseStyleAttr(
1304 CaseStmtTypeAttr::get(op.getContext(), CaseStmtType::CaseStmt));
1316void OrderedOutputOp::build(OpBuilder &builder, OperationState &result,
1317 std::function<
void()> body) {
1318 OpBuilder::InsertionGuard guard(builder);
1320 builder.createBlock(result.addRegion());
1331void ForOp::build(OpBuilder &builder, OperationState &result,
1332 int64_t lowerBound, int64_t upperBound, int64_t step,
1333 IntegerType type, StringRef name,
1334 llvm::function_ref<
void(BlockArgument)> body) {
1338 build(builder, result, lb, ub, st, name, body);
1340void ForOp::build(OpBuilder &builder, OperationState &result, Value lowerBound,
1341 Value upperBound, Value step, StringRef name,
1342 llvm::function_ref<
void(BlockArgument)> body) {
1343 OpBuilder::InsertionGuard guard(builder);
1344 build(builder, result, lowerBound, upperBound, step, name);
1345 auto *region = result.regions.front().get();
1346 builder.createBlock(region);
1347 BlockArgument blockArgument =
1348 region->addArgument(lowerBound.getType(), result.location);
1351 body(blockArgument);
1354void ForOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1356 auto *block = ®ion.front();
1357 setNameFn(block->getArgument(0), getInductionVarNameAttr());
1360ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
1361 auto &builder = parser.getBuilder();
1364 OpAsmParser::Argument inductionVariable;
1365 OpAsmParser::UnresolvedOperand lb, ub, step;
1367 SmallVector<OpAsmParser::Argument, 4> regionArgs;
1370 if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
1372 parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
1373 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
1374 parser.parseOperand(step) || parser.parseColon() ||
1375 parser.parseType(type))
1378 regionArgs.push_back(inductionVariable);
1381 regionArgs.front().type = type;
1382 if (parser.resolveOperand(lb, type, result.operands) ||
1383 parser.resolveOperand(ub, type, result.operands) ||
1384 parser.resolveOperand(step, type, result.operands))
1388 Region *body = result.addRegion();
1389 if (parser.parseRegion(*body, regionArgs))
1393 if (parser.parseOptionalAttrDict(result.attributes))
1396 if (!inductionVariable.ssaName.name.empty()) {
1397 if (!
isdigit(inductionVariable.ssaName.name[1]))
1399 result.attributes.append(
1400 {builder.getStringAttr(
"inductionVarName"),
1401 builder.getStringAttr(inductionVariable.ssaName.name.drop_front())});
1407void ForOp::print(OpAsmPrinter &p) {
1408 p <<
" " << getInductionVar() <<
" = " << getLowerBound() <<
" to "
1409 << getUpperBound() <<
" step " << getStep();
1410 p <<
" : " << getInductionVar().getType() <<
' ';
1411 p.printRegion(getRegion(),
1414 p.printOptionalAttrDict((*this)->getAttrs(), {
"inductionVarName"});
1417LogicalResult ForOp::canonicalize(
ForOp op, PatternRewriter &rewriter) {
1419 if (matchPattern(op.getLowerBound(), mlir::m_ConstantInt(&lb)) &&
1420 matchPattern(op.getUpperBound(), mlir::m_ConstantInt(&ub)) &&
1421 matchPattern(op.getStep(), mlir::m_ConstantInt(&step)) &&
1424 rewriter.replaceAllUsesWith(op.getInductionVar(), op.getLowerBound());
1426 rewriter.eraseOp(op);
1436LogicalResult BPAssignOp::verify() {
1437 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1439 "Verilog disallows procedural assignment to a net type (did you intend "
1440 "to use a variable type, e.g., sv.reg?)");
1444LogicalResult PAssignOp::verify() {
1445 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1447 "Verilog disallows procedural assignment to a net type (did you intend "
1448 "to use a variable type, e.g., sv.reg?)");
1461 static std::optional<ArraySlice> getArraySlice(Value v) {
1462 auto *op = v.getDefiningOp();
1464 return std::nullopt;
1465 return TypeSwitch<Operation *, std::optional<ArraySlice>>(op)
1466 .Case<hw::ArrayGetOp, ArrayIndexInOutOp>(
1467 [](
auto arrayIndex) -> std::optional<ArraySlice> {
1469 arrayIndex.getIndex()
1470 .template getDefiningOp<hw::ConstantOp>();
1472 return std::nullopt;
1473 return ArraySlice{arrayIndex.getInput(),
1478 -> std::optional<ArraySlice> {
1479 auto constant = slice.getLowIndex().getDefiningOp<
hw::ConstantOp>();
1481 return std::nullopt;
1483 slice.getInput(), constant,
1485 hw::type_cast<hw::ArrayType>(slice.getType()).getNumElements()};
1487 .Case<sv::IndexedPartSelectInOutOp>(
1488 [](sv::IndexedPartSelectInOutOp index)
1489 -> std::optional<ArraySlice> {
1491 if (!constant || index.getDecrement())
1492 return std::nullopt;
1493 return ArraySlice{index.getInput(),
1497 .Default([](
auto) {
return std::nullopt; });
1501 static std::optional<std::pair<ArraySlice, ArraySlice>>
1502 getAssignedRange(Operation *op) {
1503 assert((isa<PAssignOp, BPAssignOp>(op) &&
"assignments are expected"));
1504 auto srcRange = ArraySlice::getArraySlice(op->getOperand(1));
1506 return std::nullopt;
1507 auto destRange = ArraySlice::getArraySlice(op->getOperand(0));
1509 return std::nullopt;
1511 return std::make_pair(*destRange, *srcRange);
1522template <
typename AssignTy>
1524 PatternRewriter &rewriter) {
1526 auto assignedRangeOpt = ArraySlice::getAssignedRange(op);
1527 if (!assignedRangeOpt)
1530 auto [dest, src] = *assignedRangeOpt;
1531 AssignTy nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1532 bool changed =
false;
1533 SmallVector<Location> loc{op.getLoc()};
1535 while (nextAssign) {
1536 auto nextAssignedRange = ArraySlice::getAssignedRange(nextAssign);
1537 if (!nextAssignedRange)
1539 auto [nextDest, nextSrc] = *nextAssignedRange;
1541 if (dest.array != nextDest.array || src.array != nextSrc.array ||
1542 !
hw::isOffset(dest.start, nextDest.start, dest.size) ||
1546 dest.size += nextDest.size;
1547 src.size += nextSrc.size;
1549 loc.push_back(nextAssign.getLoc());
1550 rewriter.eraseOp(nextAssign);
1551 nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1558 auto resultType = hw::ArrayType::get(
1559 hw::type_cast<hw::ArrayType>(src.array.getType()).getElementType(),
1561 auto newDest = sv::IndexedPartSelectInOutOp::create(
1562 rewriter, op.getLoc(), dest.array, dest.start, dest.size);
1564 src.array, src.start);
1565 auto newLoc = rewriter.getFusedLoc(loc);
1566 auto newOp = rewriter.replaceOpWithNewOp<AssignTy>(op, newDest, newSrc);
1567 newOp->setLoc(newLoc);
1571LogicalResult PAssignOp::canonicalize(PAssignOp op, PatternRewriter &rewriter) {
1575LogicalResult BPAssignOp::canonicalize(BPAssignOp op,
1576 PatternRewriter &rewriter) {
1584void InterfaceOp::build(OpBuilder &builder, OperationState &result,
1585 StringRef sym_name, std::function<
void()> body) {
1586 OpBuilder::InsertionGuard guard(builder);
1588 result.addAttribute(InterfaceOp::getSymNameAttrName(result.name),
1589 builder.getStringAttr(sym_name));
1590 builder.createBlock(result.addRegion());
1595ModportType InterfaceOp::getModportType(StringRef modportName) {
1596 assert(lookupSymbol<InterfaceModportOp>(modportName) &&
1597 "Modport symbol not found.");
1598 auto *ctxt = getContext();
1599 return ModportType::get(
1601 SymbolRefAttr::get(ctxt, getSymName(),
1602 {SymbolRefAttr::get(ctxt, modportName)}));
1605Type InterfaceOp::getSignalType(StringRef signalName) {
1606 InterfaceSignalOp signal = lookupSymbol<InterfaceSignalOp>(signalName);
1607 assert(signal &&
"Interface signal symbol not found.");
1608 return signal.getType();
1612 ArrayAttr &portsAttr) {
1614 auto *
context = parser.getBuilder().getContext();
1616 SmallVector<Attribute, 8> ports;
1617 auto parseElement = [&]() -> ParseResult {
1618 auto direction = ModportDirectionAttr::parse(parser, {});
1622 FlatSymbolRefAttr signal;
1623 if (parser.parseAttribute(signal))
1626 ports.push_back(ModportStructAttr::get(
1627 context, cast<ModportDirectionAttr>(direction), signal));
1630 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1634 portsAttr = ArrayAttr::get(
context, ports);
1639 ArrayAttr portsAttr) {
1641 llvm::interleaveComma(portsAttr, p, [&](Attribute attr) {
1642 auto port = cast<ModportStructAttr>(attr);
1643 p << stringifyEnum(port.getDirection().getValue());
1645 p.printSymbolName(port.getSignal().getRootReference().getValue());
1650void InterfaceSignalOp::build(mlir::OpBuilder &builder,
1651 ::mlir::OperationState &state, StringRef name,
1653 build(builder, state, name, {}, mlir::TypeAttr::get(type));
1656void InterfaceModportOp::build(OpBuilder &builder, OperationState &state,
1657 StringRef name, ArrayRef<StringRef> inputs,
1658 ArrayRef<StringRef> outputs) {
1659 auto *ctxt = builder.getContext();
1660 SmallVector<Attribute, 8> directions;
1661 auto inputDir = ModportDirectionAttr::get(ctxt, ModportDirection::input);
1662 auto outputDir = ModportDirectionAttr::get(ctxt, ModportDirection::output);
1663 for (
auto input : inputs)
1664 directions.push_back(ModportStructAttr::
get(
1665 ctxt, inputDir, SymbolRefAttr::
get(ctxt, input)));
1666 for (
auto output : outputs)
1667 directions.push_back(ModportStructAttr::
get(
1668 ctxt, outputDir, SymbolRefAttr::
get(ctxt, output)));
1669 build(builder, state, name, {},
1670 ArrayAttr::get(ctxt, directions));
1673std::optional<size_t> InterfaceInstanceOp::getTargetResultIndex() {
1675 return std::nullopt;
1680void InterfaceInstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
1681 setNameFn(getResult(),
getName());
1685LogicalResult InterfaceInstanceOp::verify() {
1687 return emitOpError(
"requires non-empty name");
1692InterfaceInstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1693 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1695 return emitError(
"sv.interface.instance must exist within a region "
1696 "which has a symbol table.");
1697 auto ifaceTy = getType();
1698 auto *referencedOp =
1699 symbolTable.lookupSymbolIn(symtable, ifaceTy.getInterface());
1701 return emitError(
"Symbol not found: ") << ifaceTy.getInterface() <<
".";
1702 if (!isa<InterfaceOp>(referencedOp))
1703 return emitError(
"Symbol ")
1704 << ifaceTy.getInterface() <<
" is not an InterfaceOp.";
1711GetModportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1712 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1714 return emitError(
"sv.interface.instance must exist within a region "
1715 "which has a symbol table.");
1717 auto ifaceTy = getType();
1718 auto *referencedOp =
1719 symbolTable.lookupSymbolIn(symtable, ifaceTy.getModport());
1721 return emitError(
"Symbol not found: ") << ifaceTy.getModport() <<
".";
1722 if (!isa<InterfaceModportOp>(referencedOp))
1723 return emitError(
"Symbol ")
1724 << ifaceTy.getModport() <<
" is not an InterfaceModportOp.";
1728void GetModportOp::build(OpBuilder &builder, OperationState &state, Value value,
1730 auto ifaceTy = dyn_cast<InterfaceType>(value.getType());
1731 assert(ifaceTy &&
"GetModportOp expects an InterfaceType.");
1732 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), field);
1734 SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(), fieldAttr);
1735 build(builder, state, ModportType::get(builder.getContext(), modportSym),
1743 return dyn_cast_or_null<InterfaceModportOp>(
1747void ReadInterfaceSignalOp::build(OpBuilder &builder, OperationState &state,
1748 Value iface, StringRef signalName) {
1749 auto ifaceTy = dyn_cast<InterfaceType>(iface.getType());
1750 assert(ifaceTy &&
"ReadInterfaceSignalOp expects an InterfaceType.");
1751 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), signalName);
1752 InterfaceOp ifaceDefOp = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1753 iface.getDefiningOp(), ifaceTy.getInterface());
1755 "ReadInterfaceSignalOp could not resolve an InterfaceOp.");
1756 build(builder, state, ifaceDefOp.getSignalType(signalName), iface, fieldAttr);
1763 return dyn_cast_or_null<InterfaceSignalOp>(
1768 FlatSymbolRefAttr &signalName) {
1769 SymbolRefAttr fullSym;
1770 if (p.parseAttribute(fullSym) || fullSym.getNestedReferences().size() != 1)
1773 auto *ctxt = p.getBuilder().getContext();
1774 ifaceTy = InterfaceType::get(
1775 ctxt, FlatSymbolRefAttr::get(fullSym.getRootReference()));
1776 signalName = FlatSymbolRefAttr::get(fullSym.getLeafReference());
1781 FlatSymbolRefAttr signalName) {
1782 InterfaceType ifaceTy = dyn_cast<InterfaceType>(type);
1783 assert(ifaceTy &&
"Expected an InterfaceType");
1784 auto sym = SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(),
1790 auto ifaceTy = dyn_cast<InterfaceType>(ifaceVal.getType());
1793 InterfaceOp iface = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1794 ifaceVal.getDefiningOp(), ifaceTy.getInterface());
1797 InterfaceSignalOp signal = iface.lookupSymbol<InterfaceSignalOp>(signalName);
1805 FlatSymbolRefAttr
interface = getInterfaceType().getInterface();
1810 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1811 if (!topLevelModuleOp)
1814 return topLevelModuleOp.lookupSymbol(interface);
1817LogicalResult AssignInterfaceSignalOp::verify() {
1821LogicalResult ReadInterfaceSignalOp::verify() {
1829void WireOp::build(OpBuilder &builder, OperationState &odsState,
1831 hw::InnerSymAttr innerSym) {
1833 name = builder.getStringAttr(
"");
1838 odsState.addAttribute(
"name", name);
1844void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
1846 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
1847 if (!nameAttr.getValue().empty())
1848 setNameFn(getResult(), nameAttr.getValue());
1851std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
1854LogicalResult WireOp::canonicalize(
WireOp wire, PatternRewriter &rewriter) {
1860 if (wire.getInnerSymAttr())
1865 SmallVector<sv::ReadInOutOp> reads;
1868 for (
auto *user : wire->getUsers()) {
1869 if (
auto read = dyn_cast<sv::ReadInOutOp>(user)) {
1870 reads.push_back(read);
1875 auto assign = dyn_cast<sv::AssignOp>(user);
1878 if (!assign || write)
1894 connected = ConstantZOp::create(
1895 rewriter, wire.getLoc(),
1896 cast<InOutType>(wire.getResult().getType()).getElementType());
1897 }
else if (isa<hw::HWModuleOp>(
write->getParentOp()))
1898 connected =
write.getSrc();
1905 if (
auto *connectedOp = connected.getDefiningOp())
1906 if (!wire.getName().empty())
1907 rewriter.modifyOpInPlace(connectedOp, [&] {
1908 connectedOp->setAttr(
"sv.namehint", wire.getNameAttr());
1912 for (
auto read : reads)
1913 rewriter.replaceOp(
read, connected);
1917 rewriter.eraseOp(write);
1918 rewriter.eraseOp(wire);
1928 auto elemTy = cast<hw::InOutType>(type).getElementType();
1929 if (isa<IntegerType>(elemTy))
1930 return hw::InOutType::get(IntegerType::get(type.getContext(), width));
1931 if (isa<hw::ArrayType>(elemTy))
1932 return hw::InOutType::get(hw::ArrayType::get(
1933 cast<hw::ArrayType>(elemTy).getElementType(), width));
1937LogicalResult IndexedPartSelectInOutOp::inferReturnTypes(
1938 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1939 DictionaryAttr attrs, mlir::PropertyRef properties,
1940 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1941 Adaptor adaptor(operands, attrs, properties, regions);
1942 auto width = adaptor.getWidthAttr();
1947 width.getValue().getZExtValue());
1950 results.push_back(typ);
1954LogicalResult IndexedPartSelectInOutOp::verify() {
1955 unsigned inputWidth = 0, resultWidth = 0;
1957 auto inputElemTy = cast<InOutType>(getInput().getType()).getElementType();
1958 auto resultElemTy = cast<InOutType>(getType()).getElementType();
1959 if (
auto i = dyn_cast<IntegerType>(inputElemTy))
1960 inputWidth = i.getWidth();
1961 else if (
auto i = hw::type_cast<hw::ArrayType>(inputElemTy))
1962 inputWidth = i.getNumElements();
1964 return emitError(
"input element type must be Integer or Array");
1966 if (
auto resType = dyn_cast<IntegerType>(resultElemTy))
1967 resultWidth = resType.getWidth();
1968 else if (
auto resType = hw::type_cast<hw::ArrayType>(resultElemTy))
1969 resultWidth = resType.getNumElements();
1971 return emitError(
"result element type must be Integer or Array");
1973 if (opWidth > inputWidth)
1974 return emitError(
"slice width should not be greater than input width");
1975 if (opWidth != resultWidth)
1976 return emitError(
"result width must be equal to slice width");
1980OpFoldResult IndexedPartSelectInOutOp::fold(FoldAdaptor) {
1981 if (getType() == getInput().getType())
1990LogicalResult IndexedPartSelectOp::inferReturnTypes(
1991 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1992 DictionaryAttr attrs, mlir::PropertyRef properties,
1993 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1994 Adaptor adaptor(operands, attrs, properties, regions);
1995 auto width = adaptor.getWidthAttr();
1999 results.push_back(IntegerType::get(
context, width.getInt()));
2003LogicalResult IndexedPartSelectOp::verify() {
2006 unsigned resultWidth = cast<IntegerType>(getType()).getWidth();
2007 unsigned inputWidth = cast<IntegerType>(getInput().getType()).getWidth();
2009 if (opWidth > inputWidth)
2010 return emitError(
"slice width should not be greater than input width");
2011 if (opWidth != resultWidth)
2012 return emitError(
"result width must be equal to slice width");
2020LogicalResult StructFieldInOutOp::inferReturnTypes(
2021 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
2022 DictionaryAttr attrs, mlir::PropertyRef properties,
2023 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2024 Adaptor adaptor(operands, attrs, properties, regions);
2025 auto field = adaptor.getFieldAttr();
2030 auto resultType = structType.getFieldType(field);
2034 results.push_back(hw::InOutType::get(resultType));
2042LogicalResult AliasOp::verify() {
2044 if (getAliases().size() < 2)
2045 return emitOpError(
"alias must have at least two operands");
2058 for (
auto &op : llvm::reverse(body->getOperations())) {
2059 if (
auto instance = dyn_cast<Op>(op)) {
2060 if (
auto innerSym = instance.getInnerSym())
2061 if (innerSym->getSymName() == name)
2065 if (
auto ifdef = dyn_cast<IfDefOp>(op)) {
2067 findInstanceSymbolInBlock<Op>(name, ifdef.getThenBlock()))
2069 if (ifdef.hasElse())
2071 findInstanceSymbolInBlock<Op>(name, ifdef.getElseBlock()))
2082 return cast<hw::InstanceOp>(result.getOp());
2086 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
2087 if (!topLevelModuleOp)
2090 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2091 topLevelModuleOp.lookupSymbol(getInstance().getModule()));
2096 return findInstanceSymbolInBlock<hw::InstanceOp>(getInstance().
getName(),
2097 hwModule.getBodyBlock());
2101LogicalResult BindOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2102 auto module = (*this)->getParentOfType<mlir::ModuleOp>();
2103 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2104 symbolTable.lookupSymbolIn(module, getInstance().getModule()));
2106 return emitError(
"Referenced module doesn't exist ")
2107 << getInstance().getModule() <<
"::" << getInstance().getName();
2109 auto inst = findInstanceSymbolInBlock<hw::InstanceOp>(
2110 getInstance().
getName(), hwModule.getBodyBlock());
2112 return emitError(
"Referenced instance doesn't exist ")
2113 << getInstance().getModule() <<
"::" << getInstance().getName();
2114 if (!inst.getDoNotPrint())
2115 return emitError(
"Referenced instance isn't marked as doNotPrint");
2119void BindOp::build(OpBuilder &builder, OperationState &odsState, StringAttr mod,
2121 auto ref = hw::InnerRefAttr::get(mod, name);
2122 odsState.addAttribute(
"instance", ref);
2129void SVVerbatimSourceOp::print(OpAsmPrinter &p) {
2132 StringRef visibilityAttrName =
2133 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2134 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2135 p << visibility.getValue() <<
' ';
2137 p.printSymbolName(getSymName());
2143 SmallVector<StringRef> omittedAttrs = {getSymNameAttrName(),
"parameters",
2144 visibilityAttrName};
2146 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), omittedAttrs);
2149ParseResult SVVerbatimSourceOp::parse(OpAsmParser &parser,
2150 OperationState &result) {
2153 StringRef visibilityAttrName =
2154 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2155 StringRef visibility;
2156 if (succeeded(parser.parseOptionalKeyword(&visibility,
2157 {
"public",
"private",
"nested"}))) {
2158 result.addAttribute(visibilityAttrName,
2159 parser.getBuilder().getStringAttr(visibility));
2163 StringAttr nameAttr;
2164 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2169 ArrayAttr parameters;
2172 result.addAttribute(
"parameters", parameters);
2175 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2181LogicalResult SVVerbatimSourceOp::verify() {
2183 if (getContent().
empty())
2184 return emitOpError(
"missing or empty content attribute");
2190SVVerbatimSourceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2192 if (
auto additionalFiles = getAdditionalFiles()) {
2193 for (
auto fileRef : *additionalFiles) {
2194 auto flatRef = dyn_cast<FlatSymbolRefAttr>(fileRef);
2197 "additional_files must contain flat symbol references");
2199 auto *referencedOp =
2200 symbolTable.lookupNearestSymbolFrom(getOperation(), flatRef);
2202 return emitOpError(
"references nonexistent file ")
2203 << flatRef.getValue();
2206 if (referencedOp->getName().getStringRef() !=
"emit.file")
2207 return emitOpError(
"references ")
2208 << flatRef.getValue() <<
", which is not an emit.file";
2219SmallVector<hw::PortInfo> SVVerbatimModuleOp::getPortList() {
2220 SmallVector<hw::PortInfo> ports;
2222 auto portLocs = getPortLocs();
2223 auto portAttrs = getPerPortAttrs();
2225 for (
size_t i = 0, e = moduleType.getNumPorts(); i < e; ++i) {
2226 auto port = moduleType.getPorts()[i];
2227 LocationAttr loc = portLocs && i < portLocs->size()
2228 ? cast<LocationAttr>((*portLocs)[i])
2229 : UnknownLoc::
get(getContext());
2230 DictionaryAttr attrs = portAttrs && i < portAttrs->size()
2231 ? cast<DictionaryAttr>((*portAttrs)[i])
2232 : DictionaryAttr::
get(getContext());
2239 size_t argNum = moduleType.isOutput(i) ? moduleType.getOutputIdForPortId(i)
2240 : moduleType.getInputIdForPortId(i);
2241 ports.push_back({{port.name, port.type, dir}, argNum, attrs, loc});
2250size_t SVVerbatimModuleOp::getPortIdForInputId(
size_t idx) {
2254size_t SVVerbatimModuleOp::getPortIdForOutputId(
size_t idx) {
2258size_t SVVerbatimModuleOp::getNumPorts() {
2262size_t SVVerbatimModuleOp::getNumInputPorts() {
2266size_t SVVerbatimModuleOp::getNumOutputPorts() {
2270hw::ModuleType SVVerbatimModuleOp::getHWModuleType() {
return getModuleType(); }
2272ArrayRef<Attribute> SVVerbatimModuleOp::getAllPortAttrs() {
2273 if (
auto attrs = getPerPortAttrs())
2274 return attrs->getValue();
2278void SVVerbatimModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
2279 setPerPortAttrsAttr(ArrayAttr::get(getContext(), attrs));
2282void SVVerbatimModuleOp::removeAllPortAttrs() { removePerPortAttrsAttr(); }
2284SmallVector<Location> SVVerbatimModuleOp::getAllPortLocs() {
2285 if (
auto locs = getPortLocs()) {
2286 SmallVector<Location> result;
2287 result.reserve(locs->size());
2288 for (
auto loc : *locs)
2289 result.push_back(cast<Location>(loc));
2292 return SmallVector<Location>(
getNumPorts(), UnknownLoc::get(getContext()));
2295void SVVerbatimModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
2296 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
2299void SVVerbatimModuleOp::setHWModuleType(hw::ModuleType type) {
2300 setModuleTypeAttr(TypeAttr::get(type));
2303void SVVerbatimModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
2306 SmallVector<hw::ModulePort> ports;
2307 for (
size_t i = 0, e = currentType.getNumPorts(); i < e; ++i) {
2308 auto port = currentType.getPorts()[i];
2309 if (i < names.size())
2310 port.name = cast<StringAttr>(names[i]);
2311 ports.push_back(port);
2316void SVVerbatimModuleOp::print(OpAsmPrinter &p) {
2319 StringRef visibilityAttrName =
2320 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2321 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2322 p << visibility.getValue() <<
' ';
2324 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
2332 SmallVector<StringRef> omittedAttrs = {
2333 getSymNameAttrName(),
2334 mlir::SymbolOpInterface::getDefaultVisibilityAttrName(),
2335 getModuleTypeAttrName().getValue(),
2336 getPerPortAttrsAttrName().getValue(),
2337 getPortLocsAttrName().getValue(),
2338 getParametersAttrName().getValue()};
2340 mlir::function_interface_impl::printFunctionAttributes(p, *
this,
2344ParseResult SVVerbatimModuleOp::parse(OpAsmParser &parser,
2345 OperationState &result) {
2346 using namespace mlir::function_interface_impl;
2347 auto builder = parser.getBuilder();
2350 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2353 StringAttr nameAttr;
2354 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2359 ArrayAttr parameters;
2363 SmallVector<hw::module_like_impl::PortParse> ports;
2369 result.addAttribute(getModuleTypeAttrName(result.name), modType);
2370 result.addAttribute(
"parameters", parameters);
2374 auto unknownLoc = builder.getUnknownLoc();
2375 SmallVector<Attribute> attrs, locs;
2377 for (
auto &port : ports) {
2378 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2379 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2380 locs.push_back(loc);
2384 result.addAttribute(
"per_port_attrs", builder.getArrayAttr(attrs));
2386 result.addAttribute(
"port_locs", builder.getArrayAttr(locs));
2388 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2392 if (!result.attributes.get(
"source"))
2393 return parser.emitError(parser.getCurrentLocation(),
2394 "sv.verbatim.module requires 'source' attribute");
2399LogicalResult SVVerbatimModuleOp::verify() {
return success(); }
2402SVVerbatimModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2404 auto sourceOp = dyn_cast_or_null<SVVerbatimSourceOp>(
2405 symbolTable.lookupNearestSymbolFrom(*
this, getSourceAttr()));
2407 return emitError(
"references ") << getSourceAttr().getAttr().getValue()
2408 <<
", which is not an sv.verbatim.source";
2417sv::InterfaceInstanceOp
2422 return cast<sv::InterfaceInstanceOp>(result.getOp());
2426 auto *symbolTable = SymbolTable::getNearestSymbolTable(*
this);
2435 return findInstanceSymbolInBlock<sv::InterfaceInstanceOp>(
2436 getInstance().
getName(), &parentOp->getRegion(0).front());
2441BindInterfaceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2443 symbolTable.lookupNearestSymbolFrom(*
this, getInstance().getModule());
2445 return emitError(
"Referenced module doesn't exist ")
2446 << getInstance().getModule() <<
"::" << getInstance().getName();
2448 auto inst = findInstanceSymbolInBlock<sv::InterfaceInstanceOp>(
2449 getInstance().
getName(), &parentOp->getRegion(0).front());
2451 return emitError(
"Referenced interface doesn't exist ")
2452 << getInstance().getModule() <<
"::" << getInstance().getName();
2453 if (!inst.getDoNotPrint())
2454 return emitError(
"Referenced interface isn't marked as doNotPrint");
2463 StringAttr &terminalAttr) {
2464 SmallVector<Attribute> strings;
2465 ParseResult ret = parser.parseCommaSeparatedList([&]() {
2468 if (succeeded(parser.parseOptionalKeyword(&keyword))) {
2469 strings.push_back(parser.getBuilder().getStringAttr(keyword));
2472 if (succeeded(parser.parseAttribute(
2473 result, parser.getBuilder().getType<NoneType>()))) {
2474 strings.push_back(result);
2479 if (succeeded(ret)) {
2480 pathAttr = parser.getBuilder().getArrayAttr(
2481 ArrayRef<Attribute>(strings).drop_back());
2482 terminalAttr = cast<StringAttr>(*strings.rbegin());
2488 StringAttr terminalAttr) {
2489 llvm::interleaveComma(pathAttr, p);
2490 p <<
", " << terminalAttr;
2494LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2495 auto *table = SymbolTable::getNearestSymbolTable(*
this);
2496 auto path = dyn_cast_or_null<hw::HierPathOp>(
2497 symbolTable.lookupSymbolIn(table, getRefAttr()));
2499 return emitError(
"Referenced path doesn't exist ") << getRefAttr();
2506 if (
auto *result = cache->
getDefinition(getRefAttr().getAttr()))
2507 return cast<hw::HierPathOp>(result);
2509 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
2510 return topLevelModuleOp.lookupSymbol<hw::HierPathOp>(getRefAttr().getValue());
2518 PatternRewriter &rewriter,
2521 if (constant.getValue().isZero() == eraseIfZero) {
2522 rewriter.eraseOp(op);
2529template <
class Op,
bool EraseIfZero = false>
2531 PatternRewriter &rewriter) {
2535void AssertOp::getCanonicalizationPatterns(RewritePatternSet &results,
2537 results.add(canonicalizeImmediateVerifOp<AssertOp>);
2540void AssumeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2542 results.add(canonicalizeImmediateVerifOp<AssumeOp>);
2545void CoverOp::getCanonicalizationPatterns(RewritePatternSet &results,
2547 results.add(canonicalizeImmediateVerifOp<CoverOp, /* EraseIfZero = */ true>);
2550template <
class Op,
bool EraseIfZero = false>
2552 PatternRewriter &rewriter) {
2556void AssertConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2558 results.add(canonicalizeConcurrentVerifOp<AssertConcurrentOp>);
2561void AssumeConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2563 results.add(canonicalizeConcurrentVerifOp<AssumeConcurrentOp>);
2566void CoverConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2569 canonicalizeConcurrentVerifOp<CoverConcurrentOp, /* EraseIfZero */ true>);
2579 ArrayAttr &caseNamesArray,
2580 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
2582 SmallVector<Attribute> names;
2583 while (!p.parseOptionalKeyword(
"case")) {
2586 std::unique_ptr<Region> region = std::make_unique<Region>();
2587 if (p.parseLParen() || p.parseAttribute(
pattern) || p.parseComma() ||
2588 p.parseAttribute(name) || p.parseRParen() || p.parseRegion(*region))
2591 names.push_back(name);
2592 if (region->empty())
2593 region->push_back(
new Block());
2594 caseRegions.push_back(std::move(region));
2596 patternsArray = p.getBuilder().getArrayAttr(
patterns);
2597 caseNamesArray = p.getBuilder().getArrayAttr(names);
2604 ArrayAttr namesArray,
2605 MutableArrayRef<Region> caseRegions) {
2606 assert(patternsArray.size() == caseRegions.size());
2607 assert(patternsArray.size() == namesArray.size());
2608 for (
size_t i = 0, e = caseRegions.size(); i < e; ++i) {
2610 p <<
"case (" << patternsArray[i] <<
", " << namesArray[i] <<
") ";
2611 p.printRegion(caseRegions[i]);
2616LogicalResult GenerateCaseOp::verify() {
2617 size_t numPatterns = getCasePatterns().size();
2618 if (getCaseRegions().size() != numPatterns ||
2619 getCaseNames().size() != numPatterns)
2621 "Size of caseRegions, patterns, and caseNames must match");
2623 StringSet<> usedNames;
2624 for (Attribute name : getCaseNames()) {
2625 StringAttr nameStr = dyn_cast<StringAttr>(name);
2627 return emitOpError(
"caseNames must all be string attributes");
2628 if (usedNames.contains(nameStr.getValue()))
2629 return emitOpError(
"caseNames must be unique");
2630 usedNames.insert(nameStr.getValue());
2646 TypedAttr &result, Type type) {
2649 if (succeeded(parser.parseCustomAttributeWithFallback(attr, type))) {
2650 auto typedAttr = dyn_cast<TypedAttr>(attr);
2651 if (!typedAttr || typedAttr.getType() != type) {
2652 return parser.emitError(parser.getCurrentLocation(),
2653 "expected typed attribute with type ")
2658 if (succeeded(parser.parseOptionalColon())) {
2660 if (failed(parser.parseType(localType)) || localType != type)
2661 return parser.emitError(parser.getCurrentLocation(),
2662 "expected typed attribute with type ")
2675 TypedAttr &upperBound, TypedAttr &step,
2676 StringAttr &inductionVarName,
2677 StringAttr &genBlockName, Region &body) {
2678 auto &builder = parser.getBuilder();
2680 OpAsmParser::Argument inductionVariable;
2681 if (parser.parseArgument(inductionVariable,
true))
2682 return parser.emitError(parser.getCurrentLocation(),
2683 "expected induction variable argument");
2686 if (parser.parseEqual())
2690 Type type = inductionVariable.type;
2694 if (parser.parseKeyword(
"to"))
2701 if (parser.parseKeyword(
"step"))
2708 if (parser.parseKeyword(
"name"))
2712 if (parser.parseCustomAttributeWithFallback(
2713 genBlockName, parser.getBuilder().getType<NoneType>()))
2717 if (!
isdigit(inductionVariable.ssaName.name.front()))
2719 builder.getStringAttr(inductionVariable.ssaName.name.drop_front());
2721 SmallVector<OpAsmParser::Argument, 1> regionArgs = {inductionVariable};
2722 return parser.parseRegion(body, regionArgs);
2727 TypedAttr lowerBound, TypedAttr upperBound,
2728 TypedAttr step, StringAttr inductionVarName,
2729 StringAttr genBlockName, Region &body) {
2730 auto forOp = cast<GenerateForOp>(op);
2731 p << forOp.getInductionVar() <<
" : " << forOp.getInductionVar().getType()
2733 p.printStrippedAttrOrType(lowerBound);
2735 p.printStrippedAttrOrType(upperBound);
2737 p.printStrippedAttrOrType(step);
2739 p.printAttributeWithoutType(genBlockName);
2741 p.printRegion(body,
false,
2745LogicalResult GenerateForOp::verify() {
2746 if (getBody().getBlocks().front().getNumArguments() != 1)
2747 return emitOpError(
"must have exactly one block argument");
2748 Type type = getLowerBound().getType();
2749 if (getBody().getBlocks().front().getArgument(0).getType() != type)
2750 return emitOpError(
"block argument type must match loop bounds type");
2751 if (!isa<IntegerType>(type))
2752 return emitOpError(
"loop bounds must be integer types");
2757void GenerateForOp::getAsmBlockArgumentNames(
2759 auto *block = ®ion.front();
2760 if (
auto attr = getInductionVarNameAttr())
2761 setNameFn(block->getArgument(0), attr);
2764ModportStructAttr ModportStructAttr::get(MLIRContext *
context,
2765 ModportDirection direction,
2766 FlatSymbolRefAttr signal) {
2774ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
2775 auto builder = parser.getBuilder();
2777 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2780 StringAttr nameAttr;
2781 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2785 SmallVector<hw::module_like_impl::PortParse> ports;
2791 result.addAttribute(FuncOp::getModuleTypeAttrName(result.name), modType);
2795 auto unknownLoc = builder.getUnknownLoc();
2796 SmallVector<Attribute> attrs, inputLocs, outputLocs;
2797 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
2798 return attr && cast<Location>(attr) != unknownLoc;
2801 for (
auto &port : ports) {
2802 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2803 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2808 result.addAttribute(FuncOp::getPerArgumentAttrsAttrName(result.name),
2809 builder.getArrayAttr(attrs));
2811 if (llvm::any_of(outputLocs, nonEmptyLocsFn))
2812 result.addAttribute(FuncOp::getResultLocsAttrName(result.name),
2813 builder.getArrayAttr(outputLocs));
2815 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2819 SmallVector<OpAsmParser::Argument, 4> entryArgs;
2820 for (
auto &port : ports)
2822 entryArgs.push_back(port);
2826 auto *body = result.addRegion();
2827 llvm::SMLoc loc = parser.getCurrentLocation();
2829 mlir::OptionalParseResult parseResult =
2830 parser.parseOptionalRegion(*body, entryArgs,
2832 if (parseResult.has_value()) {
2833 if (failed(*parseResult))
2837 return parser.emitError(loc,
"expected non-empty function body");
2839 if (llvm::any_of(inputLocs, nonEmptyLocsFn))
2840 result.addAttribute(FuncOp::getInputLocsAttrName(result.name),
2841 builder.getArrayAttr(inputLocs));
2847void FuncOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2852 auto func = cast<FuncOp>(region.getParentOp());
2854 auto *block = ®ion.front();
2856 auto names = func.getModuleType().getInputNames();
2857 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
2859 setNameFn(block->getArgument(i), cast<StringAttr>(names[i]));
2863Type FuncOp::getExplicitlyReturnedType() {
2864 if (!getPerArgumentAttrs() || getNumOutputs() == 0)
2869 auto lastArgumentAttr = dyn_cast<DictionaryAttr>(
2870 getPerArgumentAttrsAttr()[getPerArgumentAttrsAttr().size() - 1]);
2873 lastArgumentAttr.getAs<UnitAttr>(getExplicitlyReturnedAttrName()))
2874 return lastArgument.type;
2878ArrayRef<Attribute> FuncOp::getAllPortAttrs() {
2879 if (getPerArgumentAttrs())
2880 return getPerArgumentAttrs()->getValue();
2884void FuncOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
2885 setPerArgumentAttrsAttr(ArrayAttr::get(getContext(), attrs));
2888void FuncOp::removeAllPortAttrs() { setPerArgumentAttrsAttr({}); }
2889SmallVector<Location> FuncOp::getAllPortLocs() {
2890 SmallVector<Location> portLocs;
2892 auto resultLocs = getResultLocsAttr();
2893 unsigned inputCount = 0;
2895 auto unknownLoc = UnknownLoc::get(getContext());
2897 auto inputLocs = getInputLocsAttr();
2898 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2899 if (modType.isOutput(i)) {
2900 auto loc = resultLocs
2902 resultLocs.getValue()[portLocs.size() - inputCount])
2904 portLocs.push_back(loc);
2906 auto loc = body ? body->getArgument(inputCount).getLoc()
2907 : (inputLocs ? cast<Location>(inputLocs[inputCount])
2909 portLocs.push_back(loc);
2916void FuncOp::setAllPortLocsAttrs(llvm::ArrayRef<mlir::Attribute> locs) {
2917 SmallVector<Attribute> resultLocs, inputLocs;
2918 unsigned inputCount = 0;
2921 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2922 if (modType.isOutput(i))
2923 resultLocs.push_back(locs[i]);
2925 body->getArgument(inputCount++).setLoc(cast<Location>(locs[i]));
2927 inputLocs.push_back(locs[i]);
2929 setResultLocsAttr(ArrayAttr::get(getContext(), resultLocs));
2931 setInputLocsAttr(ArrayAttr::get(getContext(), inputLocs));
2934SmallVector<hw::PortInfo> FuncOp::getPortList() {
return getPortList(
false); }
2937 auto modTy = getHWModuleType();
2938 auto emptyDict = DictionaryAttr::get(getContext());
2939 LocationAttr loc = getPortLoc(idx);
2940 DictionaryAttr attrs = dyn_cast_or_null<DictionaryAttr>(getPortAttrs(idx));
2943 return {modTy.getPorts()[idx],
2944 modTy.isOutput(idx) ? modTy.getOutputIdForPortId(idx)
2945 : modTy.getInputIdForPortId(idx),
2949SmallVector<hw::PortInfo> FuncOp::getPortList(
bool excludeExplicitReturn) {
2951 auto emptyDict = DictionaryAttr::get(getContext());
2952 auto skipLastArgument = getExplicitlyReturnedType() && excludeExplicitReturn;
2953 SmallVector<hw::PortInfo> retval;
2955 for (
unsigned i = 0, e = skipLastArgument ? modTy.getNumPorts() - 1
2958 DictionaryAttr attrs = emptyDict;
2959 if (
auto perArgumentAttr = getPerArgumentAttrs())
2960 if (
auto argumentAttr =
2961 dyn_cast_or_null<DictionaryAttr>((*perArgumentAttr)[i]))
2962 attrs = argumentAttr;
2964 retval.push_back({modTy.getPorts()[i],
2965 modTy.isOutput(i) ? modTy.getOutputIdForPortId(i)
2966 : modTy.getInputIdForPortId(i),
2967 attrs, portAttr[i]});
2972void FuncOp::print(OpAsmPrinter &p) {
2975 auto funcName = op.getName();
2978 StringRef visibilityAttrName =
2979 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2980 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2981 p << visibility.getValue() <<
' ';
2982 p.printSymbolName(funcName);
2984 p, op.getBody(), op.getModuleType(),
2985 op.getPerArgumentAttrsAttr()
2986 ? ArrayRef<Attribute>(op.getPerArgumentAttrsAttr().getValue())
2987 : ArrayRef<Attribute>{},
2990 mlir::function_interface_impl::printFunctionAttributes(
2992 {visibilityAttrName, getModuleTypeAttrName(),
2993 getPerArgumentAttrsAttrName(), getInputLocsAttrName(),
2994 getResultLocsAttrName()});
2996 Region &body = op->getRegion(0);
2997 if (!body.empty()) {
2999 p.printRegion(body,
false,
3008LogicalResult ReturnOp::verify() {
3009 auto func = getParentOp<sv::FuncOp>();
3010 auto funcResults = func.getResultTypes();
3011 auto returnedValues = getOperands();
3012 if (funcResults.size() != returnedValues.size())
3013 return emitOpError(
"must have same number of operands as region results.");
3015 for (
size_t i = 0, e = funcResults.size(); i < e; ++i) {
3016 if (funcResults[i] != returnedValues[i].getType()) {
3017 emitOpError(
"output types must match function. In "
3019 << i <<
", expected " << funcResults[i] <<
", but got "
3020 << returnedValues[i].getType() <<
".";
3033 mlir::Operation::result_range results) {
3034 if (!op.getExplicitlyReturnedType())
3036 return results.back();
3039Value FuncCallOp::getExplicitlyReturnedValue(sv::FuncOp op) {
3043Value FuncCallProceduralOp::getExplicitlyReturnedValue(sv::FuncOp op) {
3048FuncCallProceduralOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3049 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3050 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3052 return emitError(
"cannot find function declaration '")
3053 << getCallee() <<
"'";
3057LogicalResult FuncCallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3058 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3059 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3061 return emitError(
"cannot find function declaration '")
3062 << getCallee() <<
"'";
3065 if (referencedOp.getNumOutputs() != 1 ||
3066 !referencedOp.getExplicitlyReturnedType()) {
3067 auto diag = emitError()
3068 <<
"function called in a non-procedural region must "
3069 "return a single result";
3070 diag.attachNote(referencedOp.getLoc()) <<
"doesn't satisfy the constraint";
3081FuncDPIImportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3082 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3083 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3086 return emitError(
"cannot find function declaration '")
3087 << getCallee() <<
"'";
3088 if (!referencedOp.isDeclaration())
3089 return emitError(
"imported function must be a declaration but '")
3090 << getCallee() <<
"' is defined";
3101static LogicalResult
verify(Value clock,
bool eventExists, mlir::Location loc) {
3102 if ((!clock && eventExists) || (clock && !eventExists))
3103 return mlir::emitError(
3104 loc,
"Every clock must be associated to an even and vice-versa!");
3109LogicalResult AssertPropertyOp::verify() {
3114LogicalResult AssumePropertyOp::verify() {
3119LogicalResult CoverPropertyOp::verify() {
3129#define GET_OP_CLASSES
3130#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)
static void printGenerateFor(OpAsmPrinter &p, Operation *op, TypedAttr lowerBound, TypedAttr upperBound, TypedAttr step, StringAttr inductionVarName, StringAttr genBlockName, Region &body)
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 ParseResult parseTypedAttrWithFallback(OpAsmParser &parser, TypedAttr &result, Type type)
static void printImplicitVarInitType(OpAsmPrinter &p, Operation *op, Type varType, Value initValue, Type initType)
static LogicalResult canonicalizeConcurrentVerifOp(Op op, PatternRewriter &rewriter)
static ParseResult parseEventList(OpAsmParser &p, Attribute &eventsAttr, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &clocksOperands)
static LogicalResult verifyPackage(Package package)
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.
static ParseResult parseImplicitVarInitType(OpAsmParser &p, Type varType, std::optional< OpAsmParser::UnresolvedOperand > &initValue, Type &initType)
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 parseGenerateFor(OpAsmParser &parser, TypedAttr &lowerBound, TypedAttr &upperBound, TypedAttr &step, StringAttr &inductionVarName, StringAttr &genBlockName, Region &body)
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)
Recursively remove HW type aliases from a type and its subelements.
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.