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");
128 hw::InnerRefNamespace &ns) {
130 for (
auto symbol : symbols) {
131 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(symbol)) {
132 if (!ns.lookup(innerRef))
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() <<
"'";
156LogicalResult VerbatimOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
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) {
191LogicalResult VerbatimExprOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
196VerbatimExprOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
201void VerbatimExprSEOp::getAsmResultNames(
202 function_ref<
void(Value, StringRef)> setNameFn) {
206LogicalResult VerbatimExprSEOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
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());
243MacroDeclOp MacroRefExprOp::getReferencedMacro(
const hw::HWSymbolCache *cache) {
244 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
248MacroRefExprSEOp::getReferencedMacro(
const hw::HWSymbolCache *cache) {
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))
277MacroDeclOp MacroDefOp::getReferencedMacro(
const hw::HWSymbolCache *cache) {
278 return ::getReferencedMacro(cache, *
this, getMacroNameAttr());
281MacroDeclOp MacroRefOp::getReferencedMacro(
const hw::HWSymbolCache *cache) {
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();
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);
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);
460 odsState.addAttribute(hw::InnerSymbolTable::getInnerSymbolAttrName(),
462 odsState.addTypes(hw::InOutType::get(
elementType));
464 odsState.addOperands(initValue);
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())
490 if (!isa<AssignOp>(user))
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);
513 odsState.addAttribute(hw::InnerSymbolTable::getInnerSymbolAttrName(),
515 odsState.addTypes(hw::InOutType::get(
elementType));
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");
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)) {
1004 pattern |= unsigned(elt);
1006 auto patternType = IntegerType::get(
context, bits.size() * 2);
1007 intAttr = IntegerAttr::get(patternType, pattern);
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))
1082 Type canonicalCondType = hw::getCanonicalType(condType);
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() {
1226 if (!(hw::isHWIntegerType(getCond().getType()) ||
1227 hw::isHWEnumType(getCond().getType())))
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);
1442 Type &destType, Type &srcType) {
1444 if (parser.parseType(firstType))
1447 if (isa<InOutType, NetType, VarType>(firstType)) {
1448 destType = firstType;
1449 if (parser.parseComma() || parser.parseType(srcType))
1452 destType = InOutType::get(firstType);
1453 srcType = firstType;
1459 Type destType, Type srcType) {
1460 if (isa<InOutType>(destType)) {
1461 printer.printType(srcType);
1465 printer.printType(destType);
1467 printer.printType(srcType);
1470LogicalResult BPAssignOp::verify() {
1471 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1473 "Verilog disallows procedural assignment to a net type (did you intend "
1474 "to use a variable type, e.g., sv.reg?)");
1478LogicalResult PAssignOp::verify() {
1479 if (isa<sv::WireOp>(getDest().getDefiningOp()))
1481 "Verilog disallows procedural assignment to a net type (did you intend "
1482 "to use a variable type, e.g., sv.reg?)");
1495 static std::optional<ArraySlice> getArraySlice(Value v) {
1496 auto *op = v.getDefiningOp();
1498 return std::nullopt;
1499 return TypeSwitch<Operation *, std::optional<ArraySlice>>(op)
1500 .Case<hw::ArrayGetOp, ArrayIndexInOutOp>(
1501 [](
auto arrayIndex) -> std::optional<ArraySlice> {
1502 hw::ConstantOp constant =
1503 arrayIndex.getIndex()
1504 .template getDefiningOp<hw::ConstantOp>();
1506 return std::nullopt;
1507 return ArraySlice{arrayIndex.getInput(),
1511 .Case<hw::ArraySliceOp>([](hw::ArraySliceOp slice)
1512 -> std::optional<ArraySlice> {
1513 auto constant = slice.getLowIndex().getDefiningOp<hw::ConstantOp>();
1515 return std::nullopt;
1517 slice.getInput(), constant,
1519 hw::type_cast<hw::ArrayType>(slice.getType()).getNumElements()};
1521 .Case<sv::IndexedPartSelectInOutOp>(
1522 [](sv::IndexedPartSelectInOutOp index)
1523 -> std::optional<ArraySlice> {
1524 auto constant = index.getBase().getDefiningOp<hw::ConstantOp>();
1525 if (!constant || index.getDecrement())
1526 return std::nullopt;
1527 return ArraySlice{index.getInput(),
1531 .Default([](
auto) {
return std::nullopt; });
1535 static std::optional<std::pair<ArraySlice, ArraySlice>>
1536 getAssignedRange(Operation *op) {
1537 assert((isa<PAssignOp, BPAssignOp>(op) &&
"assignments are expected"));
1538 auto srcRange = ArraySlice::getArraySlice(op->getOperand(1));
1540 return std::nullopt;
1541 auto destRange = ArraySlice::getArraySlice(op->getOperand(0));
1543 return std::nullopt;
1545 return std::make_pair(*destRange, *srcRange);
1556template <
typename AssignTy>
1558 PatternRewriter &rewriter) {
1560 auto assignedRangeOpt = ArraySlice::getAssignedRange(op);
1561 if (!assignedRangeOpt)
1564 auto [dest, src] = *assignedRangeOpt;
1565 AssignTy nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1566 bool changed =
false;
1567 SmallVector<Location> loc{op.getLoc()};
1569 while (nextAssign) {
1570 auto nextAssignedRange = ArraySlice::getAssignedRange(nextAssign);
1571 if (!nextAssignedRange)
1573 auto [nextDest, nextSrc] = *nextAssignedRange;
1575 if (dest.array != nextDest.array || src.array != nextSrc.array ||
1576 !hw::isOffset(dest.start, nextDest.start, dest.size) ||
1577 !hw::isOffset(src.start, nextSrc.start, src.size))
1580 dest.size += nextDest.size;
1581 src.size += nextSrc.size;
1583 loc.push_back(nextAssign.getLoc());
1584 rewriter.eraseOp(nextAssign);
1585 nextAssign = dyn_cast_or_null<AssignTy>(op->getNextNode());
1592 auto resultType = hw::ArrayType::get(
1593 hw::type_cast<hw::ArrayType>(src.array.getType()).getElementType(),
1595 auto newDest = sv::IndexedPartSelectInOutOp::create(
1596 rewriter, op.getLoc(), dest.array, dest.start, dest.size);
1598 src.array, src.start);
1599 auto newLoc = rewriter.getFusedLoc(loc);
1600 auto newOp = rewriter.replaceOpWithNewOp<AssignTy>(op, newDest, newSrc);
1601 newOp->setLoc(newLoc);
1605LogicalResult PAssignOp::canonicalize(PAssignOp op, PatternRewriter &rewriter) {
1609LogicalResult BPAssignOp::canonicalize(BPAssignOp op,
1610 PatternRewriter &rewriter) {
1618void InterfaceOp::build(OpBuilder &builder, OperationState &result,
1619 StringRef sym_name, std::function<
void()> body) {
1620 OpBuilder::InsertionGuard guard(builder);
1622 result.addAttribute(InterfaceOp::getSymNameAttrName(result.name),
1623 builder.getStringAttr(sym_name));
1624 builder.createBlock(result.addRegion());
1629ModportType InterfaceOp::getModportType(StringRef modportName) {
1630 assert(lookupSymbol<InterfaceModportOp>(modportName) &&
1631 "Modport symbol not found.");
1632 auto *ctxt = getContext();
1633 return ModportType::get(
1635 SymbolRefAttr::get(ctxt, getSymName(),
1636 {SymbolRefAttr::get(ctxt, modportName)}));
1639Type InterfaceOp::getSignalType(StringRef signalName) {
1640 InterfaceSignalOp signal = lookupSymbol<InterfaceSignalOp>(signalName);
1641 assert(signal &&
"Interface signal symbol not found.");
1642 return signal.getType();
1646 ArrayAttr &portsAttr) {
1648 auto *
context = parser.getBuilder().getContext();
1650 SmallVector<Attribute, 8> ports;
1651 auto parseElement = [&]() -> ParseResult {
1652 auto direction = ModportDirectionAttr::parse(parser, {});
1656 FlatSymbolRefAttr signal;
1657 if (parser.parseAttribute(signal))
1660 ports.push_back(ModportStructAttr::get(
1661 context, cast<ModportDirectionAttr>(direction), signal));
1664 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1668 portsAttr = ArrayAttr::get(
context, ports);
1673 ArrayAttr portsAttr) {
1675 llvm::interleaveComma(portsAttr, p, [&](Attribute attr) {
1676 auto port = cast<ModportStructAttr>(attr);
1677 p << stringifyEnum(port.getDirection().getValue());
1679 p.printSymbolName(port.getSignal().getRootReference().getValue());
1684void InterfaceSignalOp::build(mlir::OpBuilder &builder,
1685 ::mlir::OperationState &state, StringRef name,
1687 build(builder, state, name, {}, mlir::TypeAttr::get(type));
1690void InterfaceModportOp::build(OpBuilder &builder, OperationState &state,
1691 StringRef name, ArrayRef<StringRef> inputs,
1692 ArrayRef<StringRef> outputs) {
1693 auto *ctxt = builder.getContext();
1694 SmallVector<Attribute, 8> directions;
1695 auto inputDir = ModportDirectionAttr::get(ctxt, ModportDirection::input);
1696 auto outputDir = ModportDirectionAttr::get(ctxt, ModportDirection::output);
1697 for (
auto input : inputs)
1698 directions.push_back(ModportStructAttr::get(
1699 ctxt, inputDir, SymbolRefAttr::get(ctxt, input)));
1700 for (
auto output : outputs)
1701 directions.push_back(ModportStructAttr::get(
1702 ctxt, outputDir, SymbolRefAttr::get(ctxt, output)));
1703 build(builder, state, name, {},
1704 ArrayAttr::get(ctxt, directions));
1707std::optional<size_t> InterfaceInstanceOp::getTargetResultIndex() {
1709 return std::nullopt;
1715 setNameFn(getResult(),
getName());
1719LogicalResult InterfaceInstanceOp::verify() {
1721 return emitOpError(
"requires non-empty name");
1726InterfaceInstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1727 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1729 return emitError(
"sv.interface.instance must exist within a region "
1730 "which has a symbol table.");
1731 auto ifaceTy = getType();
1732 auto *referencedOp =
1733 symbolTable.lookupSymbolIn(symtable, ifaceTy.getInterface());
1735 return emitError(
"Symbol not found: ") << ifaceTy.getInterface() <<
".";
1736 if (!isa<InterfaceOp>(referencedOp))
1737 return emitError(
"Symbol ")
1738 << ifaceTy.getInterface() <<
" is not an InterfaceOp.";
1745GetModportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1746 auto *symtable = SymbolTable::getNearestSymbolTable(*
this);
1748 return emitError(
"sv.interface.instance must exist within a region "
1749 "which has a symbol table.");
1751 auto ifaceTy = getType();
1752 auto *referencedOp =
1753 symbolTable.lookupSymbolIn(symtable, ifaceTy.getModport());
1755 return emitError(
"Symbol not found: ") << ifaceTy.getModport() <<
".";
1756 if (!isa<InterfaceModportOp>(referencedOp))
1757 return emitError(
"Symbol ")
1758 << ifaceTy.getModport() <<
" is not an InterfaceModportOp.";
1762void GetModportOp::build(OpBuilder &builder, OperationState &state, Value value,
1764 auto ifaceTy = dyn_cast<InterfaceType>(value.getType());
1765 assert(ifaceTy &&
"GetModportOp expects an InterfaceType.");
1766 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), field);
1768 SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(), fieldAttr);
1769 build(builder, state, ModportType::get(builder.getContext(), modportSym),
1776GetModportOp::getReferencedDecl(
const hw::HWSymbolCache &cache) {
1777 return dyn_cast_or_null<InterfaceModportOp>(
1778 cache.getDefinition(getFieldAttr()));
1781void ReadInterfaceSignalOp::build(OpBuilder &builder, OperationState &state,
1782 Value iface, StringRef signalName) {
1783 auto ifaceTy = dyn_cast<InterfaceType>(iface.getType());
1784 assert(ifaceTy &&
"ReadInterfaceSignalOp expects an InterfaceType.");
1785 auto fieldAttr = SymbolRefAttr::get(builder.getContext(), signalName);
1786 InterfaceOp ifaceDefOp = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1787 iface.getDefiningOp(), ifaceTy.getInterface());
1789 "ReadInterfaceSignalOp could not resolve an InterfaceOp.");
1790 build(builder, state, ifaceDefOp.getSignalType(signalName), iface, fieldAttr);
1796ReadInterfaceSignalOp::getReferencedDecl(
const hw::HWSymbolCache &cache) {
1797 return dyn_cast_or_null<InterfaceSignalOp>(
1798 cache.getDefinition(getSignalNameAttr()));
1802 FlatSymbolRefAttr &signalName) {
1803 SymbolRefAttr fullSym;
1804 if (p.parseAttribute(fullSym) || fullSym.getNestedReferences().size() != 1)
1807 auto *ctxt = p.getBuilder().getContext();
1808 ifaceTy = InterfaceType::get(
1809 ctxt, FlatSymbolRefAttr::get(fullSym.getRootReference()));
1810 signalName = FlatSymbolRefAttr::get(fullSym.getLeafReference());
1815 FlatSymbolRefAttr signalName) {
1816 InterfaceType ifaceTy = dyn_cast<InterfaceType>(type);
1817 assert(ifaceTy &&
"Expected an InterfaceType");
1818 auto sym = SymbolRefAttr::get(ifaceTy.getInterface().getRootReference(),
1824 auto ifaceTy = dyn_cast<InterfaceType>(ifaceVal.getType());
1827 InterfaceOp iface = SymbolTable::lookupNearestSymbolFrom<InterfaceOp>(
1828 ifaceVal.getDefiningOp(), ifaceTy.getInterface());
1831 InterfaceSignalOp signal = iface.lookupSymbol<InterfaceSignalOp>(signalName);
1838InterfaceInstanceOp::getReferencedInterface(
const hw::HWSymbolCache *cache) {
1839 FlatSymbolRefAttr
interface = getInterfaceType().getInterface();
1841 if (
auto *result = cache->getDefinition(interface))
1844 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1845 if (!topLevelModuleOp)
1848 return topLevelModuleOp.lookupSymbol(interface);
1851LogicalResult AssignInterfaceSignalOp::verify() {
1855LogicalResult ReadInterfaceSignalOp::verify() {
1863static void buildWire(OpBuilder &builder, OperationState &odsState,
1864 Type resultType, StringAttr name,
1865 hw::InnerSymAttr innerSym) {
1867 name = builder.getStringAttr(
"");
1869 odsState.addAttribute(hw::InnerSymbolTable::getInnerSymbolAttrName(),
1872 odsState.addAttribute(
"name", name);
1873 odsState.addTypes(resultType);
1876void WireOp::build(OpBuilder &builder, OperationState &odsState, Type type,
1877 StringAttr name, hw::InnerSymAttr innerSym) {
1878 if (isa<InOutType, NetType>(type))
1879 buildWire(builder, odsState, type, name, innerSym);
1881 buildWire(builder, odsState, InOutType::get(type), name, innerSym);
1888 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
1889 if (!nameAttr.getValue().empty())
1890 setNameFn(getResult(), nameAttr.getValue());
1893std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
1896LogicalResult WireOp::canonicalize(
WireOp wire, PatternRewriter &rewriter) {
1902 if (wire.getInnerSymAttr())
1907 SmallVector<sv::ReadInOutOp> reads;
1910 for (
auto *user : wire->getUsers()) {
1911 if (
auto read = dyn_cast<sv::ReadInOutOp>(user)) {
1912 reads.push_back(read);
1917 auto assign = dyn_cast<sv::AssignOp>(user);
1920 if (!assign || write)
1937 ConstantZOp::create(rewriter, wire.getLoc(),
1939 }
else if (isa<hw::HWModuleOp>(
write->getParentOp()))
1940 connected =
write.getSrc();
1947 if (
auto *connectedOp = connected.getDefiningOp())
1948 if (!wire.getName().empty())
1949 rewriter.modifyOpInPlace(connectedOp, [&] {
1950 connectedOp->setAttr(
"sv.namehint", wire.getNameAttr());
1954 for (
auto read : reads)
1955 rewriter.replaceOp(read, connected);
1959 rewriter.eraseOp(write);
1960 rewriter.eraseOp(wire);
1974 if (hw::type_isa<IntegerType>(elemType))
1975 newElem = IntegerType::get(type.getContext(), width);
1976 else if (
auto array = hw::type_dyn_cast<hw::ArrayType>(elemType))
1977 newElem = hw::ArrayType::get(array.getElementType(), width);
1983LogicalResult IndexedPartSelectInOutOp::inferReturnTypes(
1984 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
1985 DictionaryAttr
attrs, mlir::PropertyRef properties,
1986 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
1987 Adaptor adaptor(operands,
attrs, properties, regions);
1988 auto width = adaptor.getWidthAttr();
1991 auto inputType = operands[0].getType();
2001 results.push_back(resultType);
2005LogicalResult IndexedPartSelectInOutOp::verify() {
2006 unsigned inputWidth = 0, resultWidth = 0;
2010 if (
auto i = hw::type_dyn_cast<IntegerType>(inputElemTy))
2011 inputWidth = i.getWidth();
2012 else if (
auto i = hw::type_dyn_cast<hw::ArrayType>(inputElemTy))
2013 inputWidth = i.getNumElements();
2015 return emitError(
"input element type must be Integer or Array");
2017 if (
auto resType = hw::type_dyn_cast<IntegerType>(resultElemTy))
2018 resultWidth = resType.getWidth();
2019 else if (
auto resType = hw::type_dyn_cast<hw::ArrayType>(resultElemTy))
2020 resultWidth = resType.getNumElements();
2022 return emitError(
"result element type must be Integer or Array");
2024 if (opWidth > inputWidth)
2025 return emitError(
"slice width should not be greater than input width");
2026 if (opWidth != resultWidth)
2027 return emitError(
"result width must be equal to slice width");
2031OpFoldResult IndexedPartSelectInOutOp::fold(FoldAdaptor) {
2032 if (getType() == getInput().getType())
2041LogicalResult IndexedPartSelectOp::inferReturnTypes(
2042 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
2043 DictionaryAttr
attrs, mlir::PropertyRef properties,
2044 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2045 Adaptor adaptor(operands,
attrs, properties, regions);
2046 auto width = adaptor.getWidthAttr();
2050 results.push_back(IntegerType::get(
context, width.getInt()));
2054LogicalResult IndexedPartSelectOp::verify() {
2057 unsigned resultWidth = cast<IntegerType>(getType()).getWidth();
2058 unsigned inputWidth = cast<IntegerType>(getInput().getType()).getWidth();
2060 if (opWidth > inputWidth)
2061 return emitError(
"slice width should not be greater than input width");
2062 if (opWidth != resultWidth)
2063 return emitError(
"result width must be equal to slice width");
2071LogicalResult StructFieldInOutOp::inferReturnTypes(
2072 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
2073 DictionaryAttr
attrs, mlir::PropertyRef properties,
2074 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2075 Adaptor adaptor(operands,
attrs, properties, regions);
2076 auto field = adaptor.getFieldAttr();
2079 auto handleType = operands[0].getType();
2082 auto resultType = structType.getFieldType(field);
2094LogicalResult AliasOp::verify() {
2096 if (getAliases().size() < 2)
2097 return emitOpError(
"alias must have at least two operands");
2110 for (
auto &op : llvm::reverse(body->getOperations())) {
2111 if (
auto instance = dyn_cast<Op>(op)) {
2112 if (
auto innerSym = instance.getInnerSym())
2113 if (innerSym->getSymName() == name)
2117 if (
auto ifdef = dyn_cast<IfDefOp>(op)) {
2121 if (ifdef.hasElse())
2130hw::InstanceOp BindOp::getReferencedInstance(
const hw::HWSymbolCache *cache) {
2133 auto result = cache->getInnerDefinition(getInstance());
2134 return cast<hw::InstanceOp>(result.getOp());
2138 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
2139 if (!topLevelModuleOp)
2142 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2143 topLevelModuleOp.lookupSymbol(getInstance().getModule()));
2149 hwModule.getBodyBlock());
2153LogicalResult BindOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2154 auto module = (*this)->getParentOfType<mlir::ModuleOp>();
2155 auto hwModule = dyn_cast_or_null<hw::HWModuleOp>(
2156 symbolTable.lookupSymbolIn(module, getInstance().getModule()));
2158 return emitError(
"Referenced module doesn't exist ")
2159 << getInstance().getModule() <<
"::" << getInstance().getName();
2162 getInstance().
getName(), hwModule.getBodyBlock());
2164 return emitError(
"Referenced instance doesn't exist ")
2165 << getInstance().getModule() <<
"::" << getInstance().getName();
2166 if (!inst.getDoNotPrint())
2167 return emitError(
"Referenced instance isn't marked as doNotPrint");
2171void BindOp::build(OpBuilder &builder, OperationState &odsState, StringAttr mod,
2173 auto ref = hw::InnerRefAttr::get(mod, name);
2174 odsState.addAttribute(
"instance", ref);
2181void SVVerbatimSourceOp::print(OpAsmPrinter &p) {
2184 StringRef visibilityAttrName =
2185 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2186 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2187 p << visibility.getValue() <<
' ';
2189 p.printSymbolName(getSymName());
2195 SmallVector<StringRef> omittedAttrs = {getSymNameAttrName(),
"parameters",
2196 visibilityAttrName};
2198 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), omittedAttrs);
2201ParseResult SVVerbatimSourceOp::parse(OpAsmParser &parser,
2202 OperationState &result) {
2205 StringRef visibilityAttrName =
2206 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2207 StringRef visibility;
2208 if (succeeded(parser.parseOptionalKeyword(&visibility,
2209 {
"public",
"private",
"nested"}))) {
2210 result.addAttribute(visibilityAttrName,
2211 parser.getBuilder().getStringAttr(visibility));
2215 StringAttr nameAttr;
2216 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2221 ArrayAttr parameters;
2224 result.addAttribute(
"parameters", parameters);
2227 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2233LogicalResult SVVerbatimSourceOp::verify() {
2235 if (getContent().
empty())
2236 return emitOpError(
"missing or empty content attribute");
2242SVVerbatimSourceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2244 if (
auto additionalFiles = getAdditionalFiles()) {
2245 for (
auto fileRef : *additionalFiles) {
2246 auto flatRef = dyn_cast<FlatSymbolRefAttr>(fileRef);
2249 "additional_files must contain flat symbol references");
2251 auto *referencedOp =
2252 symbolTable.lookupNearestSymbolFrom(getOperation(), flatRef);
2254 return emitOpError(
"references nonexistent file ")
2255 << flatRef.getValue();
2258 if (referencedOp->getName().getStringRef() !=
"emit.file")
2259 return emitOpError(
"references ")
2260 << flatRef.getValue() <<
", which is not an emit.file";
2271SmallVector<hw::PortInfo> SVVerbatimModuleOp::getPortList() {
2272 SmallVector<hw::PortInfo> ports;
2274 auto portLocs = getPortLocs();
2275 auto portAttrs = getPerPortAttrs();
2277 for (
size_t i = 0, e = moduleType.getNumPorts(); i < e; ++i) {
2278 auto port = moduleType.getPorts()[i];
2279 LocationAttr loc = portLocs && i < portLocs->size()
2280 ? cast<LocationAttr>((*portLocs)[i])
2281 : UnknownLoc::
get(getContext());
2282 DictionaryAttr
attrs = portAttrs && i < portAttrs->size()
2283 ? cast<DictionaryAttr>((*portAttrs)[i])
2284 : DictionaryAttr::get(getContext());
2285 size_t argNum = moduleType.isOutput(i) ? moduleType.getOutputIdForPortId(i)
2286 : moduleType.getInputIdForPortId(i);
2287 ports.push_back({{port.name, port.type, port.dir}, argNum,
attrs, loc});
2292hw::PortInfo SVVerbatimModuleOp::getPort(
size_t idx) {
2296size_t SVVerbatimModuleOp::getPortIdForInputId(
size_t idx) {
2300size_t SVVerbatimModuleOp::getPortIdForOutputId(
size_t idx) {
2304size_t SVVerbatimModuleOp::getNumPorts() {
2308size_t SVVerbatimModuleOp::getNumInputPorts() {
2312size_t SVVerbatimModuleOp::getNumOutputPorts() {
2316hw::ModuleType SVVerbatimModuleOp::getHWModuleType() {
return getModuleType(); }
2318ArrayRef<Attribute> SVVerbatimModuleOp::getAllPortAttrs() {
2319 if (
auto attrs = getPerPortAttrs())
2320 return attrs->getValue();
2324void SVVerbatimModuleOp::setAllPortAttrs(ArrayRef<Attribute>
attrs) {
2325 setPerPortAttrsAttr(ArrayAttr::get(getContext(),
attrs));
2328void SVVerbatimModuleOp::removeAllPortAttrs() { removePerPortAttrsAttr(); }
2330SmallVector<Location> SVVerbatimModuleOp::getAllPortLocs() {
2331 if (
auto locs = getPortLocs()) {
2332 SmallVector<Location> result;
2333 result.reserve(locs->size());
2334 for (
auto loc : *locs)
2335 result.push_back(cast<Location>(loc));
2338 return SmallVector<Location>(
getNumPorts(), UnknownLoc::get(getContext()));
2341void SVVerbatimModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
2342 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
2345void SVVerbatimModuleOp::setHWModuleType(hw::ModuleType type) {
2346 setModuleTypeAttr(TypeAttr::get(
type));
2349void SVVerbatimModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
2352 SmallVector<hw::ModulePort> ports;
2353 for (
size_t i = 0, e = currentType.getNumPorts(); i < e; ++i) {
2354 auto port = currentType.getPorts()[i];
2355 if (i < names.size())
2356 port.name = cast<StringAttr>(names[i]);
2357 ports.push_back(port);
2362void SVVerbatimModuleOp::print(OpAsmPrinter &p) {
2365 StringRef visibilityAttrName =
2366 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2367 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2368 p << visibility.getValue() <<
' ';
2370 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
2375 hw::module_like_impl::printModuleSignatureNew(
2378 SmallVector<StringRef> omittedAttrs = {
2379 getSymNameAttrName(),
2380 mlir::SymbolOpInterface::getDefaultVisibilityAttrName(),
2381 getModuleTypeAttrName().getValue(),
2382 getPerPortAttrsAttrName().getValue(),
2383 getPortLocsAttrName().getValue(),
2384 getParametersAttrName().getValue()};
2386 mlir::function_interface_impl::printFunctionAttributes(p, *
this,
2390ParseResult SVVerbatimModuleOp::parse(OpAsmParser &parser,
2391 OperationState &result) {
2392 using namespace mlir::function_interface_impl;
2393 auto builder = parser.getBuilder();
2396 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2399 StringAttr nameAttr;
2400 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2409 SmallVector<hw::module_like_impl::PortParse> ports;
2412 hw::module_like_impl::parseModuleSignature(parser, ports, modType)))
2415 result.addAttribute(getModuleTypeAttrName(result.name), modType);
2416 result.addAttribute(
"parameters",
parameters);
2420 auto unknownLoc = builder.getUnknownLoc();
2421 SmallVector<Attribute>
attrs, locs;
2423 for (
auto &port : ports) {
2424 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2425 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2426 locs.push_back(loc);
2430 result.addAttribute(
"per_port_attrs", builder.getArrayAttr(
attrs));
2432 result.addAttribute(
"port_locs", builder.getArrayAttr(locs));
2434 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2438 if (!result.attributes.get(
"source"))
2439 return parser.emitError(parser.getCurrentLocation(),
2440 "sv.verbatim.module requires 'source' attribute");
2445LogicalResult SVVerbatimModuleOp::verify() {
return success(); }
2448SVVerbatimModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2450 auto sourceOp = dyn_cast_or_null<SVVerbatimSourceOp>(
2451 symbolTable.lookupNearestSymbolFrom(*
this, getSourceAttr()));
2453 return emitError(
"references ") << getSourceAttr().getAttr().getValue()
2454 <<
", which is not an sv.verbatim.source";
2463sv::InterfaceInstanceOp
2464BindInterfaceOp::getReferencedInstance(
const hw::HWSymbolCache *cache) {
2467 auto result = cache->getInnerDefinition(getInstance());
2468 return cast<sv::InterfaceInstanceOp>(result.getOp());
2472 auto *symbolTable = SymbolTable::getNearestSymbolTable(*
this);
2482 getInstance().
getName(), &parentOp->getRegion(0).front());
2487BindInterfaceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2489 symbolTable.lookupNearestSymbolFrom(*
this, getInstance().getModule());
2491 return emitError(
"Referenced module doesn't exist ")
2492 << getInstance().getModule() <<
"::" << getInstance().getName();
2495 getInstance().
getName(), &parentOp->getRegion(0).front());
2497 return emitError(
"Referenced interface doesn't exist ")
2498 << getInstance().getModule() <<
"::" << getInstance().getName();
2499 if (!inst.getDoNotPrint())
2500 return emitError(
"Referenced interface isn't marked as doNotPrint");
2509 StringAttr &terminalAttr) {
2510 SmallVector<Attribute> strings;
2511 ParseResult ret = parser.parseCommaSeparatedList([&]() {
2514 if (succeeded(parser.parseOptionalKeyword(&keyword))) {
2515 strings.push_back(parser.getBuilder().getStringAttr(keyword));
2518 if (succeeded(parser.parseAttribute(
2519 result, parser.getBuilder().getType<NoneType>()))) {
2520 strings.push_back(result);
2525 if (succeeded(ret)) {
2526 pathAttr = parser.getBuilder().getArrayAttr(
2527 ArrayRef<Attribute>(strings).drop_back());
2528 terminalAttr = cast<StringAttr>(*strings.rbegin());
2534 StringAttr terminalAttr) {
2535 llvm::interleaveComma(pathAttr, p);
2536 p <<
", " << terminalAttr;
2540LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2541 auto *table = SymbolTable::getNearestSymbolTable(*
this);
2542 auto path = dyn_cast_or_null<hw::HierPathOp>(
2543 symbolTable.lookupSymbolIn(table, getRefAttr()));
2545 return emitError(
"Referenced path doesn't exist ") << getRefAttr();
2550hw::HierPathOp XMRRefOp::getReferencedPath(
const hw::HWSymbolCache *cache) {
2552 if (
auto *result = cache->getDefinition(getRefAttr().getAttr()))
2553 return cast<hw::HierPathOp>(result);
2555 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
2556 return topLevelModuleOp.lookupSymbol<hw::HierPathOp>(getRefAttr().getValue());
2564 PatternRewriter &rewriter,
2567 if (constant.getValue().isZero() == eraseIfZero) {
2568 rewriter.eraseOp(op);
2575template <
class Op,
bool EraseIfZero = false>
2577 PatternRewriter &rewriter) {
2581void AssertOp::getCanonicalizationPatterns(RewritePatternSet &results,
2586void AssumeOp::getCanonicalizationPatterns(RewritePatternSet &results,
2591void CoverOp::getCanonicalizationPatterns(RewritePatternSet &results,
2596template <
class Op,
bool EraseIfZero = false>
2598 PatternRewriter &rewriter) {
2602void AssertConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2607void AssumeConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2612void CoverConcurrentOp::getCanonicalizationPatterns(RewritePatternSet &results,
2625 ArrayAttr &caseNamesArray,
2626 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
2628 SmallVector<Attribute> names;
2629 while (!p.parseOptionalKeyword(
"case")) {
2632 std::unique_ptr<Region> region = std::make_unique<Region>();
2633 if (p.parseLParen() || p.parseAttribute(pattern) || p.parseComma() ||
2634 p.parseAttribute(name) || p.parseRParen() || p.parseRegion(*region))
2637 names.push_back(name);
2638 if (region->empty())
2639 region->push_back(
new Block());
2640 caseRegions.push_back(std::move(region));
2642 patternsArray = p.getBuilder().getArrayAttr(
patterns);
2643 caseNamesArray = p.getBuilder().getArrayAttr(names);
2650 ArrayAttr namesArray,
2651 MutableArrayRef<Region> caseRegions) {
2652 assert(patternsArray.size() == caseRegions.size());
2653 assert(patternsArray.size() == namesArray.size());
2654 for (
size_t i = 0, e = caseRegions.size(); i < e; ++i) {
2656 p <<
"case (" << patternsArray[i] <<
", " << namesArray[i] <<
") ";
2657 p.printRegion(caseRegions[i]);
2662LogicalResult GenerateCaseOp::verify() {
2663 size_t numPatterns = getCasePatterns().size();
2664 if (getCaseRegions().size() != numPatterns ||
2665 getCaseNames().size() != numPatterns)
2667 "Size of caseRegions, patterns, and caseNames must match");
2669 StringSet<> usedNames;
2670 for (Attribute name : getCaseNames()) {
2671 StringAttr nameStr = dyn_cast<StringAttr>(name);
2673 return emitOpError(
"caseNames must all be string attributes");
2674 if (usedNames.contains(nameStr.getValue()))
2675 return emitOpError(
"caseNames must be unique");
2676 usedNames.insert(nameStr.getValue());
2692 TypedAttr &result, Type type) {
2695 if (succeeded(parser.parseCustomAttributeWithFallback(attr, type))) {
2696 auto typedAttr = dyn_cast<TypedAttr>(attr);
2697 if (!typedAttr || typedAttr.getType() != type) {
2698 return parser.emitError(parser.getCurrentLocation(),
2699 "expected typed attribute with type ")
2704 if (succeeded(parser.parseOptionalColon())) {
2706 if (failed(parser.parseType(localType)) || localType != type)
2707 return parser.emitError(parser.getCurrentLocation(),
2708 "expected typed attribute with type ")
2721 TypedAttr &upperBound, TypedAttr &step,
2722 StringAttr &inductionVarName,
2723 StringAttr &genBlockName, Region &body) {
2724 auto &builder = parser.getBuilder();
2726 OpAsmParser::Argument inductionVariable;
2727 if (parser.parseArgument(inductionVariable,
true))
2728 return parser.emitError(parser.getCurrentLocation(),
2729 "expected induction variable argument");
2732 if (parser.parseEqual())
2736 Type type = inductionVariable.type;
2740 if (parser.parseKeyword(
"to"))
2747 if (parser.parseKeyword(
"step"))
2754 if (parser.parseKeyword(
"name"))
2758 if (parser.parseCustomAttributeWithFallback(
2759 genBlockName, parser.getBuilder().getType<NoneType>()))
2763 if (!
isdigit(inductionVariable.ssaName.name.front()))
2765 builder.getStringAttr(inductionVariable.ssaName.name.drop_front());
2767 SmallVector<OpAsmParser::Argument, 1> regionArgs = {inductionVariable};
2768 return parser.parseRegion(body, regionArgs);
2773 TypedAttr lowerBound, TypedAttr upperBound,
2774 TypedAttr step, StringAttr inductionVarName,
2775 StringAttr genBlockName, Region &body) {
2776 auto forOp = cast<GenerateForOp>(op);
2777 p << forOp.getInductionVar() <<
" : " << forOp.getInductionVar().getType()
2779 p.printStrippedAttrOrType(lowerBound);
2781 p.printStrippedAttrOrType(upperBound);
2783 p.printStrippedAttrOrType(step);
2785 p.printAttributeWithoutType(genBlockName);
2787 p.printRegion(body,
false,
2791LogicalResult GenerateForOp::verify() {
2792 if (getBody().getBlocks().front().getNumArguments() != 1)
2793 return emitOpError(
"must have exactly one block argument");
2794 Type type = getLowerBound().getType();
2795 if (getBody().getBlocks().front().getArgument(0).getType() != type)
2796 return emitOpError(
"block argument type must match loop bounds type");
2797 if (!isa<IntegerType>(type))
2798 return emitOpError(
"loop bounds must be integer types");
2803void GenerateForOp::getAsmBlockArgumentNames(
2805 auto *block = ®ion.front();
2806 if (
auto attr = getInductionVarNameAttr())
2807 setNameFn(block->getArgument(0), attr);
2810ModportStructAttr ModportStructAttr::get(MLIRContext *
context,
2811 ModportDirection direction,
2812 FlatSymbolRefAttr signal) {
2820ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
2821 auto builder = parser.getBuilder();
2823 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2826 StringAttr nameAttr;
2827 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
2831 SmallVector<hw::module_like_impl::PortParse> ports;
2834 hw::module_like_impl::parseModuleSignature(parser, ports, modType)))
2837 result.addAttribute(FuncOp::getModuleTypeAttrName(result.name), modType);
2841 auto unknownLoc = builder.getUnknownLoc();
2842 SmallVector<Attribute>
attrs, inputLocs, outputLocs;
2843 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
2844 return attr && cast<Location>(attr) != unknownLoc;
2847 for (
auto &port : ports) {
2848 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
2849 auto loc = port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc;
2850 (port.direction == hw::PortInfo::Direction::Output ? outputLocs : inputLocs)
2854 result.addAttribute(FuncOp::getPerArgumentAttrsAttrName(result.name),
2855 builder.getArrayAttr(
attrs));
2857 if (llvm::any_of(outputLocs, nonEmptyLocsFn))
2858 result.addAttribute(FuncOp::getResultLocsAttrName(result.name),
2859 builder.getArrayAttr(outputLocs));
2861 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2865 SmallVector<OpAsmParser::Argument, 4> entryArgs;
2866 for (
auto &port : ports)
2867 if (port.direction != hw::ModulePort::Direction::Output)
2868 entryArgs.push_back(port);
2872 auto *body = result.addRegion();
2873 llvm::SMLoc loc = parser.getCurrentLocation();
2875 mlir::OptionalParseResult parseResult =
2876 parser.parseOptionalRegion(*body, entryArgs,
2878 if (parseResult.has_value()) {
2879 if (failed(*parseResult))
2883 return parser.emitError(loc,
"expected non-empty function body");
2885 if (llvm::any_of(inputLocs, nonEmptyLocsFn))
2886 result.addAttribute(FuncOp::getInputLocsAttrName(result.name),
2887 builder.getArrayAttr(inputLocs));
2893void FuncOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2898 auto func = cast<FuncOp>(region.getParentOp());
2900 auto *block = ®ion.front();
2902 auto names = func.getModuleType().getInputNames();
2903 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
2905 setNameFn(block->getArgument(i), cast<StringAttr>(names[i]));
2909Type FuncOp::getExplicitlyReturnedType() {
2910 if (!getPerArgumentAttrs() || getNumOutputs() == 0)
2915 auto lastArgumentAttr = dyn_cast<DictionaryAttr>(
2916 getPerArgumentAttrsAttr()[getPerArgumentAttrsAttr().size() - 1]);
2918 if (lastArgument.dir == hw::ModulePort::Output && lastArgumentAttr &&
2919 lastArgumentAttr.getAs<UnitAttr>(getExplicitlyReturnedAttrName()))
2920 return lastArgument.type;
2924ArrayRef<Attribute> FuncOp::getAllPortAttrs() {
2925 if (getPerArgumentAttrs())
2926 return getPerArgumentAttrs()->getValue();
2930void FuncOp::setAllPortAttrs(ArrayRef<Attribute>
attrs) {
2931 setPerArgumentAttrsAttr(ArrayAttr::get(getContext(),
attrs));
2934void FuncOp::removeAllPortAttrs() { setPerArgumentAttrsAttr({}); }
2935SmallVector<Location> FuncOp::getAllPortLocs() {
2936 SmallVector<Location> portLocs;
2938 auto resultLocs = getResultLocsAttr();
2939 unsigned inputCount = 0;
2941 auto unknownLoc = UnknownLoc::get(getContext());
2943 auto inputLocs = getInputLocsAttr();
2944 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2945 if (modType.isOutput(i)) {
2946 auto loc = resultLocs
2948 resultLocs.getValue()[portLocs.size() - inputCount])
2950 portLocs.push_back(loc);
2952 auto loc = body ? body->getArgument(inputCount).getLoc()
2953 : (inputLocs ? cast<Location>(inputLocs[inputCount])
2955 portLocs.push_back(loc);
2962void FuncOp::setAllPortLocsAttrs(llvm::ArrayRef<mlir::Attribute> locs) {
2963 SmallVector<Attribute> resultLocs, inputLocs;
2964 unsigned inputCount = 0;
2967 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
2968 if (modType.isOutput(i))
2969 resultLocs.push_back(locs[i]);
2971 body->getArgument(inputCount++).setLoc(cast<Location>(locs[i]));
2973 inputLocs.push_back(locs[i]);
2975 setResultLocsAttr(ArrayAttr::get(getContext(), resultLocs));
2977 setInputLocsAttr(ArrayAttr::get(getContext(), inputLocs));
2980SmallVector<hw::PortInfo> FuncOp::getPortList() {
return getPortList(
false); }
2982hw::PortInfo FuncOp::getPort(
size_t idx) {
2983 auto modTy = getHWModuleType();
2984 auto emptyDict = DictionaryAttr::get(getContext());
2985 LocationAttr loc = getPortLoc(idx);
2986 DictionaryAttr
attrs = dyn_cast_or_null<DictionaryAttr>(getPortAttrs(idx));
2989 return {modTy.getPorts()[idx],
2990 modTy.isOutput(idx) ? modTy.getOutputIdForPortId(idx)
2991 : modTy.getInputIdForPortId(idx),
2995SmallVector<hw::PortInfo> FuncOp::getPortList(
bool excludeExplicitReturn) {
2997 auto emptyDict = DictionaryAttr::get(getContext());
2998 auto skipLastArgument = getExplicitlyReturnedType() && excludeExplicitReturn;
2999 SmallVector<hw::PortInfo> retval;
3001 for (
unsigned i = 0, e = skipLastArgument ? modTy.getNumPorts() - 1
3002 : modTy.getNumPorts();
3004 DictionaryAttr
attrs = emptyDict;
3005 if (
auto perArgumentAttr = getPerArgumentAttrs())
3006 if (
auto argumentAttr =
3007 dyn_cast_or_null<DictionaryAttr>((*perArgumentAttr)[i]))
3008 attrs = argumentAttr;
3010 retval.push_back({modTy.getPorts()[i],
3011 modTy.isOutput(i) ? modTy.getOutputIdForPortId(i)
3012 : modTy.getInputIdForPortId(i),
3013 attrs, portAttr[i]});
3018void FuncOp::print(OpAsmPrinter &p) {
3021 auto funcName = op.getName();
3024 StringRef visibilityAttrName =
3025 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
3026 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
3027 p << visibility.getValue() <<
' ';
3028 p.printSymbolName(funcName);
3029 hw::module_like_impl::printModuleSignatureNew(
3030 p, op.getBody(), op.getModuleType(),
3031 op.getPerArgumentAttrsAttr()
3032 ? ArrayRef<Attribute>(op.getPerArgumentAttrsAttr().getValue())
3033 : ArrayRef<Attribute>{},
3036 mlir::function_interface_impl::printFunctionAttributes(
3038 {visibilityAttrName, getModuleTypeAttrName(),
3039 getPerArgumentAttrsAttrName(), getInputLocsAttrName(),
3040 getResultLocsAttrName()});
3042 Region &body = op->getRegion(0);
3043 if (!body.empty()) {
3045 p.printRegion(body,
false,
3054LogicalResult ReturnOp::verify() {
3055 auto func = getParentOp<sv::FuncOp>();
3056 auto funcResults = func.getResultTypes();
3057 auto returnedValues = getOperands();
3058 if (funcResults.size() != returnedValues.size())
3059 return emitOpError(
"must have same number of operands as region results.");
3061 for (
size_t i = 0, e = funcResults.size(); i < e; ++i) {
3062 if (funcResults[i] != returnedValues[i].getType()) {
3063 emitOpError(
"output types must match function. In "
3065 << i <<
", expected " << funcResults[i] <<
", but got "
3066 << returnedValues[i].getType() <<
".";
3079 mlir::Operation::result_range results) {
3080 if (!op.getExplicitlyReturnedType())
3082 return results.back();
3085Value FuncCallOp::getExplicitlyReturnedValue(sv::FuncOp op) {
3089Value FuncCallProceduralOp::getExplicitlyReturnedValue(sv::FuncOp op) {
3094FuncCallProceduralOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3095 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3096 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3098 return emitError(
"cannot find function declaration '")
3099 << getCallee() <<
"'";
3103LogicalResult FuncCallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3104 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3105 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3107 return emitError(
"cannot find function declaration '")
3108 << getCallee() <<
"'";
3111 if (referencedOp.getNumOutputs() != 1 ||
3112 !referencedOp.getExplicitlyReturnedType()) {
3113 auto diag = emitError()
3114 <<
"function called in a non-procedural region must "
3115 "return a single result";
3116 diag.attachNote(referencedOp.getLoc()) <<
"doesn't satisfy the constraint";
3127FuncDPIImportOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3128 auto referencedOp = dyn_cast_or_null<sv::FuncOp>(
3129 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr()));
3132 return emitError(
"cannot find function declaration '")
3133 << getCallee() <<
"'";
3134 if (!referencedOp.isDeclaration())
3135 return emitError(
"imported function must be a declaration but '")
3136 << getCallee() <<
"' is defined";
3147static LogicalResult
verify(Value clock,
bool eventExists, mlir::Location loc) {
3148 if ((!clock && eventExists) || (clock && !eventExists))
3149 return mlir::emitError(
3150 loc,
"Every clock must be associated to an even and vice-versa!");
3155LogicalResult AssertPropertyOp::verify() {
3160LogicalResult AssumePropertyOp::verify() {
3165LogicalResult CoverPropertyOp::verify() {
3175#define GET_OP_CLASSES
3176#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)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
if(parseOptionalKeywordOrOptionalString(parser, result.rawName, found)) return failure()
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)
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)
static ParseResult parseSVHandleAssignmentTypes(OpAsmParser &parser, Type &destType, Type &srcType)
Parse the assignment type suffix.
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 printSVHandleAssignmentTypes(OpAsmPrinter &printer, Operation *, Type destType, Type srcType)
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'.
static void buildWire(OpBuilder &builder, OperationState &odsState, Type resultType, StringAttr name, hw::InnerSymAttr innerSym)
void printXMRPath(OpAsmPrinter &p, XMROp op, ArrayAttr pathAttr, StringAttr terminalAttr)
static InstancePath empty
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
CasePattern(CasePatternKind kind)
create(array_value, low_index, ret_type)
list[hw.ParamDeclAttr] parameters(self)
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.
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.
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function 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.
mlir::Type getHandleOfElementType(mlir::Type handleType, mlir::Type elementType)
Return a handle of the same kind (NetType or VarType) as handleType, wrapping elementType instead.
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 getHandleElementType(mlir::Type type)
Return the element type of an SV handle type or null if the operand is not an SV lvalue (NetType or V...
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