23#include "mlir/IR/Builders.h"
24#include "mlir/IR/Matchers.h"
25#include "mlir/IR/PatternMatch.h"
26#include "mlir/Interfaces/FunctionImplementation.h"
27#include "llvm/ADT/BitVector.h"
28#include "llvm/ADT/SmallPtrSet.h"
29#include "llvm/ADT/StringSet.h"
43 llvm_unreachable(
"unknown PortDirection");
47 hw::ArrayType arrayType =
49 assert(arrayType &&
"expected array type");
50 unsigned indexWidth = index.getType().getIntOrFloatBitWidth();
51 auto requiredWidth = llvm::Log2_64_Ceil(arrayType.getNumElements());
52 return requiredWidth == 0 ? (indexWidth == 0 || indexWidth == 1)
53 : indexWidth == requiredWidth;
58 struct IsCombClassifier :
public TypeOpVisitor<IsCombClassifier, bool> {
59 bool visitInvalidTypeOp(Operation *op) {
return false; }
60 bool visitUnhandledTypeOp(Operation *op) {
return true; }
63 return (op->getDialect() && op->getDialect()->getNamespace() ==
"comb") ||
69 if (
auto structCreate = dyn_cast_or_null<StructCreateOp>(inputOp)) {
70 return structCreate.getOperand(fieldIndex);
74 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
75 if (structInject.getFieldIndex() != fieldIndex)
77 return structInject.getNewValue();
83 ArrayRef<Attribute>
attrs) {
85 return ArrayAttr::get(
context, {});
88 if (a && !cast<DictionaryAttr>(a).
empty()) {
93 return ArrayAttr::get(
context, {});
104 auto module = cast<HWModuleOp>(region.getParentOp());
106 auto *block = ®ion.front();
107 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
108 auto name =
module.getInputName(i);
110 setNameFn(block->getArgument(i), name);
127 Attribute value, ArrayAttr moduleParameters,
129 bool disallowParamRefs) {
132 if (isa<IntegerAttr>(value) || isa<FloatAttr>(value) ||
133 isa<StringAttr>(value) || isa<ParamVerbatimAttr>(value))
137 if (
auto expr = dyn_cast<ParamExprAttr>(value)) {
138 for (
auto op : expr.getOperands())
147 if (
auto parameterRef = dyn_cast<ParamDeclRefAttr>(value)) {
148 auto nameAttr = parameterRef.getName();
152 if (disallowParamRefs) {
153 instanceError([&](
auto &diag) {
154 diag <<
"parameter " << nameAttr
155 <<
" cannot be used as a default value for a parameter";
162 for (
auto param : moduleParameters) {
163 auto paramAttr = cast<ParamDeclAttr>(param);
164 if (paramAttr.getName() != nameAttr)
168 if (paramAttr.getType() == parameterRef.getType())
171 instanceError([&](
auto &diag) {
172 diag <<
"parameter " << nameAttr <<
" used with type "
173 << parameterRef.getType() <<
"; should have type "
174 << paramAttr.getType();
180 instanceError([&](
auto &diag) {
181 diag <<
"use of unknown parameter " << nameAttr;
187 instanceError([&](
auto &diag) {
188 diag <<
"invalid parameter value " << value;
202 bool disallowParamRefs) {
204 [&](
const std::function<bool(InFlightDiagnostic &)> &fn) {
206 auto diag = usingOp->emitOpError();
208 diag.attachNote(module->getLoc()) <<
"module declared here";
213 module->getAttrOfType<ArrayAttr>(
"parameters"),
214 emitError, disallowParamRefs);
228 for (
auto [i, barg] : llvm::enumerate(bodyRegion.getArguments())) {
229 inputIdx[info.at(i).name.str()] = i;
234 for (
auto [i, outputInfo] : llvm::enumerate(
info.getOutputs())) {
235 outputIdx[outputInfo.name.str()] = i;
261#include "circt/Dialect/HW/HWCanonicalization.cpp.inc"
268void ConstantOp::print(OpAsmPrinter &p) {
270 if (getType() == getValueAttr().getType()) {
271 p.printAttribute(getValueAttr());
274 p.printAttributeWithoutType(getValueAttr());
275 p <<
" : " << getType();
277 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
280ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
281 auto loc = parser.getCurrentLocation();
285 bool isTrue = succeeded(parser.parseOptionalKeyword(
"true"));
286 if (isTrue || succeeded(parser.parseOptionalKeyword(
"false"))) {
287 value = APInt(1, isTrue);
288 if (failed(parser.parseOptionalColon()))
289 type = parser.getBuilder().getI1Type();
290 }
else if (parser.parseInteger(value) || parser.parseColon()) {
293 if (!type && parser.parseType(type))
295 if (parser.parseOptionalAttrDict(result.attributes))
302 return parser.emitError(loc,
"expected an integer type, but got ") << type;
303 unsigned width = intType.getWidth();
304 if (value.isNegative() ? value.getSignificantBits() > width
305 : value.getActiveBits() > width)
306 return parser.emitError(loc,
"constant out of range for type ") << type;
308 result.addAttribute(
"value",
309 IntegerAttr::get(intType, value.sextOrTrunc(width)));
310 result.addTypes(type);
314LogicalResult ConstantOp::verify() {
318 return emitError(
"hw.constant must have an integer result type");
321 if (getValueAttr().getType() != intType)
322 return emitError(
"hw.constant attribute type ")
323 << getValueAttr().getType() <<
" doesn't match the result type "
331void ConstantOp::build(OpBuilder &builder, OperationState &result,
332 const APInt &value) {
334 auto type = IntegerType::get(builder.getContext(), value.getBitWidth());
335 auto attr = builder.getIntegerAttr(type, value);
336 return build(builder, result, type, attr);
341void ConstantOp::build(OpBuilder &builder, OperationState &result,
343 return build(builder, result, value.getType(), value);
350void ConstantOp::build(OpBuilder &builder, OperationState &result, Type type,
354 builder, result, type,
355 builder.getIntegerAttr(intType, APInt(intType.getWidth(), (uint64_t)value,
360void ConstantOp::getAsmResultNames(
361 function_ref<
void(Value, StringRef)> setNameFn) {
362 Type intTy = getType();
363 auto intCst = getValue();
367 return setNameFn(getResult(), intCst.isZero() ?
"false" :
"true");
371 SmallVector<char, 32> specialNameBuffer;
372 llvm::raw_svector_ostream specialName(specialNameBuffer);
373 specialName <<
'c' << intCst <<
'_';
374 if (
auto alias = dyn_cast<TypeAliasType>(intTy))
375 specialName << alias.getRef().getLeafReference().getValue();
377 specialName << intTy;
378 setNameFn(getResult(), specialName.str());
381OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
382 assert(adaptor.getOperands().empty() &&
"constant has no operands");
383 return getValueAttr();
394 ArrayRef<StringRef> ignoredAttrs = {}) {
395 auto names = op.getAttributeNames();
396 llvm::SmallDenseSet<StringRef> nameSet;
397 nameSet.reserve(names.size() + ignoredAttrs.size());
398 nameSet.insert(names.begin(), names.end());
399 nameSet.insert(ignoredAttrs.begin(), ignoredAttrs.end());
400 return llvm::any_of(op->getAttrs(), [&](
auto namedAttr) {
401 return !nameSet.contains(namedAttr.getName());
407 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
408 if (nameAttr && !nameAttr.getValue().empty())
409 setNameFn(getResult(), nameAttr.getValue());
412std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
414OpFoldResult WireOp::fold(FoldAdaptor adaptor) {
423LogicalResult WireOp::canonicalize(WireOp wire, PatternRewriter &rewriter) {
429 if (wire.getInnerSymAttr())
433 if (wire.getInput() == wire.getResult())
438 if (
auto *inputOp = wire.getInput().getDefiningOp())
440 rewriter.modifyOpInPlace(inputOp,
441 [&] { inputOp->setAttr(
"sv.namehint", name); });
443 rewriter.replaceOp(wire, wire.getInput());
453 if (
auto typeAlias = dyn_cast<TypeAliasType>(type))
454 type = typeAlias.getCanonicalType();
456 if (
auto structType = dyn_cast<StructType>(type)) {
457 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
459 return op->emitOpError(
"expected array attribute for constant of type ")
461 if (structType.getElements().size() != arrayAttr.size())
462 return op->emitOpError(
"array attribute (")
463 << arrayAttr.size() <<
") has wrong size for struct constant ("
464 << structType.getElements().size() <<
")";
466 for (
auto [attr, fieldInfo] :
467 llvm::zip(arrayAttr.getValue(), structType.getElements())) {
471 }
else if (
auto arrayType = dyn_cast<ArrayType>(type)) {
472 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
474 return op->emitOpError(
"expected array attribute for constant of type ")
476 if (arrayType.getNumElements() != arrayAttr.size())
477 return op->emitOpError(
"array attribute (")
478 << arrayAttr.size() <<
") has wrong size for array constant ("
479 << arrayType.getNumElements() <<
")";
482 for (
auto attr : arrayAttr.getValue()) {
486 }
else if (
auto arrayType = dyn_cast<UnpackedArrayType>(type)) {
487 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
489 return op->emitOpError(
"expected array attribute for constant of type ")
492 if (arrayType.getNumElements() != arrayAttr.size())
493 return op->emitOpError(
"array attribute (")
495 <<
") has wrong size for unpacked array constant ("
496 << arrayType.getNumElements() <<
")";
498 for (
auto attr : arrayAttr.getValue()) {
502 }
else if (
auto enumType = dyn_cast<EnumType>(type)) {
503 auto stringAttr = dyn_cast<StringAttr>(attr);
505 return op->emitOpError(
"expected string attribute for constant of type ")
507 }
else if (
auto intType = dyn_cast<IntegerType>(type)) {
509 auto intAttr = dyn_cast<IntegerAttr>(attr);
511 return op->emitOpError(
"expected integer attribute for constant of type ")
514 if (intAttr.getValue().getBitWidth() != intType.getWidth())
515 return op->emitOpError(
"hw.constant attribute bitwidth "
516 "doesn't match return type");
517 }
else if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
518 if (typedAttr.getType() != type)
519 return op->emitOpError(
"typed attr doesn't match the return type ")
522 return op->emitOpError(
"unknown element type ") << type;
527LogicalResult AggregateConstantOp::verify() {
531OpFoldResult AggregateConstantOp::fold(FoldAdaptor) {
return getFieldsAttr(); }
539 if (p.parseType(resultType) || p.parseEqual() ||
540 p.parseAttribute(value, resultType))
547 p << resultType <<
" = ";
548 p.printAttributeWithoutType(value);
551LogicalResult ParamValueOp::verify() {
554 getValue(), (*this)->getParentOfType<hw::HWModuleOp>(), *
this);
557OpFoldResult ParamValueOp::fold(FoldAdaptor adaptor) {
558 assert(adaptor.getOperands().empty() &&
"hw.param.value has no operands");
559 return getValueAttr();
568 return isa<HWModuleLike, InstanceOp>(moduleOrInstance);
574 return TypeSwitch<Operation *, FunctionType>(moduleOrInstance)
575 .Case<InstanceOp>([](
auto instance) {
576 SmallVector<Type> inputs(instance->getOperandTypes());
577 SmallVector<Type> results(instance->getResultTypes());
578 return FunctionType::get(instance->getContext(), inputs, results);
581 [](
auto mod) {
return mod.getHWModuleType().getFuncType(); })
582 .Default([](Operation *op) {
583 return cast<FunctionType>(
584 cast<mlir::FunctionOpInterface>(op).getFunctionType());
592 auto nameAttr =
module->getAttrOfType<StringAttr>("verilogName");
596 if (
auto symbol = dyn_cast<mlir::SymbolOpInterface>(module))
597 return symbol.getNameAttr();
601template <
typename ModuleTy>
603buildModule(OpBuilder &builder, OperationState &result, StringAttr name,
605 ArrayRef<NamedAttribute> attributes, StringAttr comment) {
606 using namespace mlir::function_interface_impl;
609 result.addAttribute(ModuleTy::getSymNameAttrName(result.name), name);
611 SmallVector<Attribute> perPortAttrs;
612 SmallVector<ModulePort> portTypes;
614 for (
auto elt : ports) {
615 portTypes.push_back(elt);
616 llvm::SmallVector<NamedAttribute> portAttrs;
618 llvm::copy(elt.attrs, std::back_inserter(portAttrs));
619 perPortAttrs.push_back(builder.getDictionaryAttr(portAttrs));
624 parameters = builder.getArrayAttr({});
627 auto type = ModuleType::get(builder.getContext(), portTypes);
628 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name),
629 TypeAttr::get(type));
630 result.addAttribute(
"per_port_attrs",
632 result.addAttribute(
"parameters", parameters);
634 comment = builder.getStringAttr(
"");
635 result.addAttribute(
"comment", comment);
636 result.addAttributes(attributes);
642 MLIRContext *
context, ArrayRef<std::pair<unsigned, PortInfo>> insertArgs,
643 ArrayRef<unsigned> removeArgs, ArrayRef<Attribute> oldArgNames,
644 ArrayRef<Type> oldArgTypes, ArrayRef<Attribute> oldArgAttrs,
645 ArrayRef<Location> oldArgLocs, SmallVector<Attribute> &newArgNames,
646 SmallVector<Type> &newArgTypes, SmallVector<Attribute> &newArgAttrs,
647 SmallVector<Location> &newArgLocs, Block *body =
nullptr) {
652 assert(llvm::is_sorted(insertArgs,
653 [](
auto &a,
auto &b) {
return a.first < b.first; }) &&
654 "insertArgs must be in ascending order");
655 assert(llvm::is_sorted(removeArgs, [](
auto &a,
auto &b) {
return a < b; }) &&
656 "removeArgs must be in ascending order");
659 auto oldArgCount = oldArgTypes.size();
660 auto newArgCount = oldArgCount + insertArgs.size() - removeArgs.size();
661 assert((
int)newArgCount >= 0);
663 newArgNames.reserve(newArgCount);
664 newArgTypes.reserve(newArgCount);
665 newArgAttrs.reserve(newArgCount);
666 newArgLocs.reserve(newArgCount);
668 auto emptyDictAttr = DictionaryAttr::get(
context, {});
669 auto unknownLoc = UnknownLoc::get(
context);
671 BitVector erasedIndices;
673 erasedIndices.resize(oldArgCount + insertArgs.size());
675 for (
unsigned argIdx = 0, idx = 0; argIdx <= oldArgCount; ++argIdx, ++idx) {
677 while (!insertArgs.empty() && insertArgs[0].first == argIdx) {
678 auto port = insertArgs[0].second;
679 newArgNames.push_back(port.name);
680 newArgTypes.push_back(port.type);
681 newArgAttrs.push_back(port.attrs ? port.attrs : emptyDictAttr);
682 insertArgs = insertArgs.drop_front();
683 LocationAttr loc = port.loc ? port.loc : unknownLoc;
684 newArgLocs.push_back(loc);
686 body->insertArgument(idx++, port.type, loc);
688 if (argIdx == oldArgCount)
692 bool removed =
false;
693 while (!removeArgs.empty() && removeArgs[0] == argIdx) {
694 removeArgs = removeArgs.drop_front();
700 erasedIndices.set(idx);
702 newArgNames.push_back(oldArgNames[argIdx]);
703 newArgTypes.push_back(oldArgTypes[argIdx]);
704 newArgAttrs.push_back(oldArgAttrs.empty() ? emptyDictAttr
705 : oldArgAttrs[argIdx]);
706 newArgLocs.push_back(oldArgLocs[argIdx]);
711 body->eraseArguments(erasedIndices);
713 assert(newArgNames.size() == newArgCount);
714 assert(newArgTypes.size() == newArgCount);
715 assert(newArgAttrs.size() == newArgCount);
716 assert(newArgLocs.size() == newArgCount);
730[[deprecated]]
static void
732 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
733 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
734 ArrayRef<unsigned> removeInputs,
735 ArrayRef<unsigned> removeOutputs, Block *body =
nullptr) {
736 auto moduleOp = cast<HWModuleLike>(op);
737 auto *
context = moduleOp.getContext();
740 auto oldArgNames = moduleOp.getInputNames();
741 auto oldArgTypes = moduleOp.getInputTypes();
742 auto oldArgAttrs = moduleOp.getAllInputAttrs();
743 auto oldArgLocs = moduleOp.getInputLocs();
745 auto oldResultNames = moduleOp.getOutputNames();
746 auto oldResultTypes = moduleOp.getOutputTypes();
747 auto oldResultAttrs = moduleOp.getAllOutputAttrs();
748 auto oldResultLocs = moduleOp.getOutputLocs();
751 SmallVector<Attribute> newArgNames, newResultNames;
752 SmallVector<Type> newArgTypes, newResultTypes;
753 SmallVector<Attribute> newArgAttrs, newResultAttrs;
754 SmallVector<Location> newArgLocs, newResultLocs;
757 oldArgTypes, oldArgAttrs, oldArgLocs, newArgNames,
758 newArgTypes, newArgAttrs, newArgLocs, body);
761 oldResultTypes, oldResultAttrs, oldResultLocs,
762 newResultNames, newResultTypes, newResultAttrs,
766 auto fnty = FunctionType::get(
context, newArgTypes, newResultTypes);
768 moduleOp.setHWModuleType(modty);
769 moduleOp.setAllInputAttrs(newArgAttrs);
770 moduleOp.setAllOutputAttrs(newResultAttrs);
772 newArgLocs.append(newResultLocs.begin(), newResultLocs.end());
773 moduleOp.setAllPortLocs(newArgLocs);
776void HWModuleOp::build(OpBuilder &builder, OperationState &result,
778 ArrayAttr parameters,
779 ArrayRef<NamedAttribute> attributes, StringAttr comment,
780 bool shouldEnsureTerminator) {
785 auto *bodyRegion = result.regions[0].get();
787 bodyRegion->push_back(body);
790 auto unknownLoc = builder.getUnknownLoc();
792 auto loc = port.loc ? Location(port.loc) : unknownLoc;
793 auto type = port.type;
794 body->addArgument(type, loc);
798 auto unknownLocAttr = cast<LocationAttr>(unknownLoc);
799 SmallVector<Attribute> resultLocs;
801 resultLocs.push_back(port.loc ? port.loc : unknownLocAttr);
802 result.addAttribute(
"result_locs", builder.getArrayAttr(resultLocs));
804 if (shouldEnsureTerminator)
805 HWModuleOp::ensureTerminator(*bodyRegion, builder, result.location);
808void HWModuleOp::build(OpBuilder &builder, OperationState &result,
809 StringAttr name, ArrayRef<PortInfo> ports,
810 ArrayAttr parameters,
811 ArrayRef<NamedAttribute> attributes,
812 StringAttr comment) {
813 build(builder, result, name,
ModulePortInfo(ports), parameters, attributes,
817void HWModuleOp::build(OpBuilder &builder, OperationState &odsState,
820 ArrayRef<NamedAttribute> attributes,
821 StringAttr comment) {
822 build(builder, odsState, name, ports, parameters, attributes, comment,
824 auto *bodyRegion = odsState.regions[0].get();
825 OpBuilder::InsertionGuard guard(builder);
827 builder.setInsertionPointToEnd(&bodyRegion->front());
828 modBuilder(builder, accessor);
830 llvm::SmallVector<Value> outputOperands = accessor.getOutputOperands();
831 hw::OutputOp::create(builder, odsState.location, outputOperands);
834void HWModuleOp::modifyPorts(
835 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
836 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
837 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
845StringAttr HWModuleExternOp::getVerilogModuleNameAttr() {
846 if (
auto vName = getVerilogNameAttr())
849 return getSymNameAttr();
852StringAttr HWModuleGeneratedOp::getVerilogModuleNameAttr() {
853 if (
auto vName = getVerilogNameAttr()) {
856 return getSymNameAttr();
859void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
861 StringRef verilogName, ArrayAttr parameters,
862 ArrayRef<NamedAttribute> attributes) {
867 LocationAttr unknownLoc = builder.getUnknownLoc();
868 SmallVector<Attribute> portLocs;
869 for (
auto elt : ports)
870 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
871 result.addAttribute(
"port_locs", builder.getArrayAttr(portLocs));
873 if (!verilogName.empty())
874 result.addAttribute(
"verilogName", builder.getStringAttr(verilogName));
877void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
878 StringAttr name, ArrayRef<PortInfo> ports,
879 StringRef verilogName, ArrayAttr parameters,
880 ArrayRef<NamedAttribute> attributes) {
881 build(builder, result, name,
ModulePortInfo(ports), verilogName, parameters,
885void HWModuleExternOp::modifyPorts(
886 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
887 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
888 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
893void HWModuleExternOp::appendOutputs(
894 ArrayRef<std::pair<StringAttr, Value>> outputs) {}
896void HWModuleGeneratedOp::build(OpBuilder &builder, OperationState &result,
897 FlatSymbolRefAttr genKind, StringAttr name,
899 StringRef verilogName, ArrayAttr parameters,
900 ArrayRef<NamedAttribute> attributes) {
904 LocationAttr unknownLoc = builder.getUnknownLoc();
905 SmallVector<Attribute> portLocs;
906 for (
auto elt : ports)
907 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
908 result.addAttribute(
"port_locs", builder.getArrayAttr(portLocs));
910 result.addAttribute(
"generatorKind", genKind);
911 if (!verilogName.empty())
912 result.addAttribute(
"verilogName", builder.getStringAttr(verilogName));
915void HWModuleGeneratedOp::build(OpBuilder &builder, OperationState &result,
916 FlatSymbolRefAttr genKind, StringAttr name,
917 ArrayRef<PortInfo> ports, StringRef verilogName,
918 ArrayAttr parameters,
919 ArrayRef<NamedAttribute> attributes) {
920 build(builder, result, genKind, name,
ModulePortInfo(ports), verilogName,
921 parameters, attributes);
924void HWModuleGeneratedOp::modifyPorts(
925 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
926 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
927 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
932void HWModuleGeneratedOp::appendOutputs(
933 ArrayRef<std::pair<StringAttr, Value>> outputs) {}
936 for (
auto &argAttr :
attrs)
937 if (argAttr.getName() == name)
942template <
typename ModuleTy>
944 OperationState &result) {
946 using namespace mlir::function_interface_impl;
947 auto builder = parser.getBuilder();
948 auto loc = parser.getCurrentLocation();
951 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
955 if (parser.parseSymbolName(nameAttr,
956 ModuleTy::getSymNameAttrName(result.name),
961 FlatSymbolRefAttr kindAttr;
962 if constexpr (std::is_same_v<ModuleTy, HWModuleGeneratedOp>) {
963 if (parser.parseComma() ||
964 parser.parseAttribute(kindAttr,
"generatorKind", result.attributes)) {
970 ArrayAttr parameters;
974 SmallVector<module_like_impl::PortParse> ports;
980 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
984 parser.emitError(loc,
"explicit `parameters` attributes not allowed");
988 result.addAttribute(
"parameters", parameters);
989 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name), modType);
993 SmallVector<Attribute>
attrs;
994 for (
auto &port : ports)
995 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
997 auto nonEmptyAttrsFn = [](Attribute attr) {
998 return attr && !cast<DictionaryAttr>(attr).empty();
1000 if (llvm::any_of(
attrs, nonEmptyAttrsFn))
1001 result.addAttribute(ModuleTy::getPerPortAttrsAttrName(result.name),
1002 builder.getArrayAttr(
attrs));
1005 auto unknownLoc = builder.getUnknownLoc();
1006 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
1007 return attr && cast<Location>(attr) != unknownLoc;
1009 SmallVector<Attribute> locs;
1010 StringAttr portLocsAttrName;
1011 if constexpr (std::is_same_v<ModuleTy, HWModuleOp>) {
1014 portLocsAttrName = ModuleTy::getResultLocsAttrName(result.name);
1015 for (
auto &port : ports)
1017 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
1020 portLocsAttrName = ModuleTy::getPortLocsAttrName(result.name);
1021 for (
auto &port : ports)
1022 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
1024 if (llvm::any_of(locs, nonEmptyLocsFn))
1025 result.addAttribute(portLocsAttrName, builder.getArrayAttr(locs));
1028 SmallVector<OpAsmParser::Argument, 4> entryArgs;
1029 for (
auto &port : ports)
1031 entryArgs.push_back(port);
1034 auto *body = result.addRegion();
1035 if (std::is_same_v<ModuleTy, HWModuleOp>) {
1036 if (parser.parseRegion(*body, entryArgs))
1039 HWModuleOp::ensureTerminator(*body, parser.getBuilder(), result.location);
1044ParseResult HWModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1048ParseResult HWModuleExternOp::parse(OpAsmParser &parser,
1049 OperationState &result) {
1053ParseResult HWModuleGeneratedOp::parse(OpAsmParser &parser,
1054 OperationState &result) {
1059 if (
auto mod = dyn_cast<HWModuleLike>(op))
1060 return mod.getHWModuleType().getFuncType();
1061 return cast<FunctionType>(
1062 cast<mlir::FunctionOpInterface>(op).getFunctionType());
1065template <
typename ModuleTy>
1069 StringRef visibilityAttrName =
1070 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
1071 if (
auto visibility = mod.getOperation()->template getAttrOfType<StringAttr>(
1072 visibilityAttrName))
1073 p << visibility.getValue() <<
' ';
1076 p.printSymbolName(mod.getName());
1077 if (
auto gen = dyn_cast<HWModuleGeneratedOp>(mod.getOperation())) {
1079 p.printSymbolName(gen.getGeneratorKind());
1087 SmallVector<StringRef, 3> omittedAttrs;
1088 omittedAttrs.push_back(mod.getSymNameAttrName());
1089 if (isa<HWModuleGeneratedOp>(mod.getOperation()))
1090 omittedAttrs.push_back(
"generatorKind");
1091 if constexpr (std::is_same_v<ModuleTy, HWModuleOp>)
1092 omittedAttrs.push_back(mod.getResultLocsAttrName());
1094 omittedAttrs.push_back(mod.getPortLocsAttrName());
1095 omittedAttrs.push_back(mod.getModuleTypeAttrName());
1096 omittedAttrs.push_back(mod.getPerPortAttrsAttrName());
1097 omittedAttrs.push_back(mod.getParametersAttrName());
1098 omittedAttrs.push_back(visibilityAttrName);
1100 mod.getOperation()->template getAttrOfType<StringAttr>(
"comment"))
1101 if (cmt.getValue().empty())
1102 omittedAttrs.push_back(
"comment");
1104 mlir::function_interface_impl::printFunctionAttributes(p, mod.getOperation(),
1108void HWModuleExternOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1109void HWModuleGeneratedOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1111void HWModuleOp::print(OpAsmPrinter &p) {
1115 Region &body = getBody();
1116 if (!body.empty()) {
1118 p.printRegion(body,
false,
1124 assert(isa<HWModuleLike>(module) &&
1125 "verifier hook should only be called on modules");
1127 if (
auto portLocs = module->getAttrOfType<ArrayAttr>(
"port_locs"))
1128 if (!portLocs.empty() && portLocs.size() != module.getNumPorts())
1129 return module->emitOpError("requires ")
1130 << module.getNumPorts() << " port locations but got "
1133 for (
auto port : module.getPortList()) {
1135 port.type.walk([&](Type type) {
1138 auto &dialect = type.getDialect();
1143 result = interface->verifyHWModulePortType(
1144 [&] { return module->emitOpError(); }, port.dir, type);
1150 SmallPtrSet<Attribute, 4> paramNames;
1153 for (auto param : module->getAttrOfType<ArrayAttr>("parameters")) {
1154 auto paramAttr = cast<ParamDeclAttr>(param);
1158 if (!paramNames.insert(paramAttr.getName()).second)
1159 return module->emitOpError("parameter ")
1160 << paramAttr << " has the same name as a previous parameter";
1163 auto value = paramAttr.getValue();
1167 auto typedValue = dyn_cast<TypedAttr>(value);
1169 return module->emitOpError("parameter ")
1170 << paramAttr << " should have a typed value; has value
" << value;
1172 if (typedValue.getType() != paramAttr.getType())
1173 return module->emitOpError("parameter
")
1174 << paramAttr << " should have type
" << paramAttr.getType()
1175 << "; has type
" << typedValue.getType();
1177 // Verify that this is a valid parameter value, disallowing parameter
1178 // references. We could allow parameters to refer to each other in the
1179 // future with lexical ordering if there is a need.
1180 if (failed(checkParameterInContext(value, module, module,
1181 /*disallowParamRefs=*/true)))
1187LogicalResult HWModuleOp::verify() {
1188 if (failed(verifyModuleCommon(*this)))
1191 auto type = getModuleType();
1192 auto *body = getBodyBlock();
1194 // Verify the number of block arguments.
1195 auto numInputs = type.getNumInputs();
1196 if (body->getNumArguments() != numInputs)
1197 return emitOpError("entry block must have
")
1198 << numInputs << " arguments to match module signature
";
1203LogicalResult HWModuleExternOp::verify() { return verifyModuleCommon(*this); }
1205std::pair<StringAttr, BlockArgument>
1206HWModuleOp::insertInput(unsigned index, StringAttr name, Type ty) {
1207 // Find a unique name for the wire.
1209 auto ports = getPortList();
1210 for (auto port : ports)
1211 ns.newName(port.name.getValue());
1212 auto nameAttr = StringAttr::get(getContext(), ns.newName(name.getValue()));
1214 Block *body = getBodyBlock();
1216 // Create a new port for the host clock.
1218 port.name = nameAttr;
1219 port.dir = ModulePort::Direction::Input;
1221 modifyModulePorts(getOperation(), {std::make_pair(index, port)}, {}, {}, {},
1224 // Add a new argument.
1225 return {nameAttr, body->getArgument(index)};
1228void HWModuleOp::insertOutputs(unsigned index,
1229 ArrayRef<std::pair<StringAttr, Value>> outputs) {
1231 auto output = cast<OutputOp>(getBodyBlock()->getTerminator());
1232 assert(index <= output->getNumOperands() && "invalid output index
");
1234 // Rewrite the port list of the module.
1235 SmallVector<std::pair<unsigned, PortInfo>> indexedNewPorts;
1236 for (auto &[name, value] : outputs) {
1239 port.dir = ModulePort::Direction::Output;
1240 port.type = value.getType();
1241 indexedNewPorts.emplace_back(index, port);
1243 modifyModulePorts(getOperation(), {}, indexedNewPorts, {}, {},
1246 // Rewrite the output op.
1247 for (auto &[name, value] : outputs)
1248 output->insertOperands(index++, value);
1251void HWModuleOp::appendOutputs(ArrayRef<std::pair<StringAttr, Value>> outputs) {
1252 return insertOutputs(getNumOutputPorts(), outputs);
1255void HWModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1256 mlir::OpAsmSetValueNameFn setNameFn) {
1257 getAsmBlockArgumentNamesImpl(region, setNameFn);
1260void HWModuleExternOp::getAsmBlockArgumentNames(
1261 mlir::Region ®ion, mlir::OpAsmSetValueNameFn setNameFn) {
1262 getAsmBlockArgumentNamesImpl(region, setNameFn);
1265template <typename ModTy>
1266static SmallVector<Location> getAllPortLocs(ModTy module) {
1267 auto locs = module.getPortLocs();
1269 SmallVector<Location> retval;
1270 retval.reserve(locs->size());
1271 for (auto l : *locs)
1272 retval.push_back(cast<Location>(l));
1273 // Either we have a length of 0 or the correct length
1274 assert(!locs->size() || locs->size() == module.getNumPorts());
1277 return SmallVector<Location>(module.getNumPorts(),
1278 UnknownLoc::get(module.getContext()));
1281SmallVector<Location> HWModuleOp::getAllPortLocs() {
1282 SmallVector<Location> portLocs;
1283 portLocs.reserve(getNumPorts());
1284 auto resultLocs = getResultLocsAttr();
1285 unsigned inputCount = 0;
1286 auto modType = getModuleType();
1287 auto unknownLoc = UnknownLoc::get(getContext());
1288 auto *body = getBodyBlock();
1289 for (unsigned i = 0, e = getNumPorts(); i < e; ++i) {
1290 if (modType.isOutput(i)) {
1291 auto loc = resultLocs
1293 resultLocs.getValue()[portLocs.size() - inputCount])
1295 portLocs.push_back(loc);
1297 auto loc = body ? body->getArgument(inputCount).getLoc() : unknownLoc;
1298 portLocs.push_back(loc);
1305SmallVector<Location> HWModuleExternOp::getAllPortLocs() {
1306 return ::getAllPortLocs(*this);
1309SmallVector<Location> HWModuleGeneratedOp::getAllPortLocs() {
1310 return ::getAllPortLocs(*this);
1313void HWModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1314 SmallVector<Attribute> resultLocs;
1315 unsigned inputCount = 0;
1316 auto modType = getModuleType();
1317 auto *body = getBodyBlock();
1318 for (unsigned i = 0, e = getNumPorts(); i < e; ++i) {
1319 if (modType.isOutput(i))
1320 resultLocs.push_back(locs[i]);
1322 body->getArgument(inputCount++).setLoc(cast<Location>(locs[i]));
1324 setResultLocsAttr(ArrayAttr::get(getContext(), resultLocs));
1327void HWModuleExternOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1328 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
1331void HWModuleGeneratedOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1332 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
1335template <typename ModTy>
1336static void setAllPortNames(ArrayRef<Attribute> names, ModTy module) {
1337 auto numInputs = module.getNumInputPorts();
1338 SmallVector<Attribute> argNames(names.begin(), names.begin() + numInputs);
1339 SmallVector<Attribute> resNames(names.begin() + numInputs, names.end());
1340 auto oldType = module.getModuleType();
1341 SmallVector<ModulePort> newPorts(oldType.getPorts().begin(),
1342 oldType.getPorts().end());
1343 for (size_t i = 0UL, e = newPorts.size(); i != e; ++i)
1344 newPorts[i].name = cast<StringAttr>(names[i]);
1345 auto newType = ModuleType::get(module.getContext(), newPorts);
1346 module.setModuleType(newType);
1349void HWModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
1350 ::setAllPortNames(names, *this);
1353void HWModuleExternOp::setAllPortNames(ArrayRef<Attribute> names) {
1354 ::setAllPortNames(names, *this);
1357void HWModuleGeneratedOp::setAllPortNames(ArrayRef<Attribute> names) {
1358 ::setAllPortNames(names, *this);
1361ArrayRef<Attribute> HWModuleOp::getAllPortAttrs() {
1362 auto attrs = getPerPortAttrs();
1363 if (attrs && !attrs->empty())
1364 return attrs->getValue();
1368ArrayRef<Attribute> HWModuleExternOp::getAllPortAttrs() {
1369 auto attrs = getPerPortAttrs();
1370 if (attrs && !attrs->empty())
1371 return attrs->getValue();
1375ArrayRef<Attribute> HWModuleGeneratedOp::getAllPortAttrs() {
1376 auto attrs = getPerPortAttrs();
1377 if (attrs && !attrs->empty())
1378 return attrs->getValue();
1382void HWModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1383 setPerPortAttrsAttr(arrayOrEmpty(getContext(), attrs));
1386void HWModuleExternOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1387 setPerPortAttrsAttr(arrayOrEmpty(getContext(), attrs));
1390void HWModuleGeneratedOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1391 setPerPortAttrsAttr(arrayOrEmpty(getContext(), attrs));
1394void HWModuleOp::removeAllPortAttrs() {
1395 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1398void HWModuleExternOp::removeAllPortAttrs() {
1399 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1402void HWModuleGeneratedOp::removeAllPortAttrs() {
1403 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1406// This probably does really unexpected stuff when you change the number of
1408template <typename ModTy>
1409static void setHWModuleType(ModTy &mod, ModuleType type) {
1410 auto argAttrs = mod.getAllInputAttrs();
1411 auto resAttrs = mod.getAllOutputAttrs();
1412 mod.setModuleTypeAttr(TypeAttr::get(type));
1413 unsigned newNumArgs = type.getNumInputs();
1414 unsigned newNumResults = type.getNumOutputs();
1416 auto emptyDict = DictionaryAttr::get(mod.getContext());
1417 argAttrs.resize(newNumArgs, emptyDict);
1418 resAttrs.resize(newNumResults, emptyDict);
1420 SmallVector<Attribute> attrs;
1421 attrs.append(argAttrs.begin(), argAttrs.end());
1422 attrs.append(resAttrs.begin(), resAttrs.end());
1425 return mod.removeAllPortAttrs();
1426 mod.setAllPortAttrs(attrs);
1429void HWModuleOp::setHWModuleType(ModuleType type) {
1430 return ::setHWModuleType(*this, type);
1433void HWModuleExternOp::setHWModuleType(ModuleType type) {
1434 return ::setHWModuleType(*this, type);
1437void HWModuleGeneratedOp::setHWModuleType(ModuleType type) {
1438 return ::setHWModuleType(*this, type);
1443Operation *HWModuleGeneratedOp::getGeneratorKindOp() {
1444 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1445 return topLevelModuleOp.lookupSymbol(getGeneratorKind());
1449HWModuleGeneratedOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1450 auto *referencedKind =
1451 symbolTable.lookupNearestSymbolFrom(*this, getGeneratorKindAttr());
1453 if (referencedKind == nullptr)
1454 return emitError("Cannot find generator definition
'")
1455 << getGeneratorKind() << "'";
1457 if (!isa<HWGeneratorSchemaOp>(referencedKind))
1458 return emitError("Symbol resolved to
'")
1459 << referencedKind->getName()
1460 << "' which is not a HWGeneratorSchemaOp
";
1462 auto referencedKindOp = dyn_cast<HWGeneratorSchemaOp>(referencedKind);
1463 auto paramRef = referencedKindOp.getRequiredAttrs();
1464 auto dict = (*this)->getAttrDictionary();
1465 for (auto str : paramRef) {
1466 auto strAttr = dyn_cast<StringAttr>(str);
1468 return emitError("Unknown attribute type, expected a
string");
1469 if (!dict.get(strAttr.getValue()))
1470 return emitError("Missing attribute
'") << strAttr.getValue() << "'";
1476LogicalResult HWModuleGeneratedOp::verify() {
1477 return verifyModuleCommon(*this);
1480void HWModuleGeneratedOp::getAsmBlockArgumentNames(
1481 mlir::Region ®ion, mlir::OpAsmSetValueNameFn setNameFn) {
1482 getAsmBlockArgumentNamesImpl(region, setNameFn);
1485LogicalResult HWModuleOp::verifyBody() { return success(); }
1487template <typename ModuleTy>
1488static SmallVector<PortInfo> getPortList(ModuleTy &mod) {
1489 auto modTy = mod.getHWModuleType();
1490 auto emptyDict = DictionaryAttr::get(mod.getContext());
1491 SmallVector<PortInfo> retval;
1492 auto locs = mod.getAllPortLocs();
1493 for (unsigned i = 0, e = modTy.getNumPorts(); i < e; ++i) {
1494 LocationAttr loc = locs[i];
1495 DictionaryAttr attrs =
1496 dyn_cast_or_null<DictionaryAttr>(mod.getPortAttrs(i));
1499 retval.push_back({modTy.getPorts()[i],
1500 modTy.isOutput(i) ? modTy.getOutputIdForPortId(i)
1501 : modTy.getInputIdForPortId(i),
1507template <typename ModuleTy>
1508static PortInfo getPort(ModuleTy &mod, size_t idx) {
1509 auto modTy = mod.getHWModuleType();
1510 auto emptyDict = DictionaryAttr::get(mod.getContext());
1511 LocationAttr loc = mod.getPortLoc(idx);
1512 DictionaryAttr attrs =
1513 dyn_cast_or_null<DictionaryAttr>(mod.getPortAttrs(idx));
1516 return {modTy.getPorts()[idx],
1517 modTy.isOutput(idx) ? modTy.getOutputIdForPortId(idx)
1518 : modTy.getInputIdForPortId(idx),
1522//===----------------------------------------------------------------------===//
1524//===----------------------------------------------------------------------===//
1527void InstanceOp::build(OpBuilder &builder, OperationState &result,
1528 Operation *module, StringAttr name,
1529 ArrayRef<Value> inputs, ArrayAttr parameters,
1530 InnerSymAttr innerSym) {
1532 parameters = builder.getArrayAttr({});
1534 auto mod = cast<hw::HWModuleLike>(module);
1535 auto argNames = builder.getArrayAttr(mod.getInputNames());
1536 auto resultNames = builder.getArrayAttr(mod.getOutputNames());
1538 // Try to resolve the parameterized module type. If failed, use the module's
1539 // parmeterized type. If the client doesn't fix this error, the verifier will
1541 ModuleType modType = mod.getHWModuleType();
1542 FailureOr<ModuleType> resolvedModType = modType.resolveParametricTypes(
1543 parameters, result.location, /*emitErrors=*/false);
1544 if (succeeded(resolvedModType))
1545 modType = *resolvedModType;
1546 FunctionType funcType = resolvedModType->getFuncType();
1547 build(builder, result, funcType.getResults(), name,
1548 FlatSymbolRefAttr::get(SymbolTable::getSymbolName(module)), inputs,
1549 argNames, resultNames, parameters, innerSym, /*doNotPrint=*/{});
1552std::optional<size_t> InstanceOp::getTargetResultIndex() {
1553 // Inner symbols on instance operations target the op not any result.
1554 return std::nullopt;
1557LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1558 return instance_like_impl::verifyInstanceOfHWModule(
1559 *this, getModuleNameAttr(), getInputs(), getResultTypes(), getArgNames(),
1560 getResultNames(), getParameters(), symbolTable);
1563LogicalResult InstanceOp::verify() {
1564 auto module = (*this)->getParentOfType<HWModuleOp>();
1568 auto moduleParameters = module->getAttrOfType<ArrayAttr>("parameters
");
1569 instance_like_impl::EmitErrorFn emitError =
1570 [&](const std::function<bool(InFlightDiagnostic &)> &fn) {
1571 auto diag = emitOpError();
1573 diag.attachNote(module->getLoc()) << "module declared here
";
1575 return instance_like_impl::verifyParameterStructure(
1576 getParameters(), moduleParameters, emitError);
1579ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
1580 StringAttr instanceNameAttr;
1581 InnerSymAttr innerSym;
1582 FlatSymbolRefAttr moduleNameAttr;
1583 SmallVector<OpAsmParser::UnresolvedOperand, 4> inputsOperands;
1584 SmallVector<Type, 1> inputsTypes, allResultTypes;
1585 ArrayAttr argNames, resultNames, parameters;
1586 auto noneType = parser.getBuilder().getType<NoneType>();
1588 if (parser.parseAttribute(instanceNameAttr, noneType, "instanceName
",
1592 if (succeeded(parser.parseOptionalKeyword("sym
"))) {
1593 // Parsing an optional symbol name doesn't fail, so no need to check the
1595 if (parser.parseCustomAttributeWithFallback(innerSym))
1597 result.addAttribute(InnerSymbolTable::getInnerSymbolAttrName(), innerSym);
1600 llvm::SMLoc parametersLoc, inputsOperandsLoc;
1601 if (parser.parseAttribute(moduleNameAttr, noneType, "moduleName
",
1602 result.attributes) ||
1603 parser.getCurrentLocation(¶metersLoc) ||
1604 parseOptionalParameterList(parser, parameters) ||
1605 parseInputPortList(parser, inputsOperands, inputsTypes, argNames) ||
1606 parser.resolveOperands(inputsOperands, inputsTypes, inputsOperandsLoc,
1608 parser.parseArrow() ||
1609 parseOutputPortList(parser, allResultTypes, resultNames) ||
1610 parser.parseOptionalAttrDict(result.attributes)) {
1614 result.addAttribute("argNames
", argNames);
1615 result.addAttribute("resultNames
", resultNames);
1616 result.addAttribute("parameters
", parameters);
1617 result.addTypes(allResultTypes);
1621void InstanceOp::print(OpAsmPrinter &p) {
1623 p.printAttributeWithoutType(getInstanceNameAttr());
1624 if (auto attr = getInnerSymAttr()) {
1629 p.printAttributeWithoutType(getModuleNameAttr());
1630 printOptionalParameterList(p, *this, getParameters());
1631 printInputPortList(p, *this, getInputs(), getInputs().getTypes(),
1634 printOutputPortList(p, *this, getResultTypes(), getResultNames());
1636 p.printOptionalAttrDict(
1637 (*this)->getAttrs(),
1638 /*elidedAttrs=*/{"instanceName
",
1639 InnerSymbolTable::getInnerSymbolAttrName(), "moduleName
",
1640 "argNames
", "resultNames
", "parameters
"});
1643//===----------------------------------------------------------------------===//
1645//===----------------------------------------------------------------------===//
1648LogicalResult OutputOp::verify() {
1649 // Check that the we (hw.output) have the same number of operands as our
1650 // region has results.
1652 if (auto mod = dyn_cast<HWModuleOp>((*this)->getParentOp()))
1653 modType = mod.getHWModuleType();
1655 emitOpError("must have a module parent
");
1658 auto modResults = modType.getOutputTypes();
1659 OperandRange outputValues = getOperands();
1660 if (modResults.size() != outputValues.size()) {
1661 emitOpError("must have same number of operands as region results.
");
1665 // Check that the types of our operands and the region's results match.
1666 for (size_t i = 0, e = modResults.size(); i < e; ++i) {
1667 if (modResults[i] != outputValues[i].getType()) {
1668 emitOpError("output types must match module. In
"
1670 << i << ", expected
" << modResults[i] << ", but got
"
1671 << outputValues[i].getType() << ".
";
1679//===----------------------------------------------------------------------===//
1681//===----------------------------------------------------------------------===//
1683static ParseResult parseSliceTypes(OpAsmParser &p, Type &srcType,
1686 if (p.parseType(type))
1687 return p.emitError(p.getCurrentLocation(), "Expected type
");
1688 auto arrType = type_dyn_cast<ArrayType>(type);
1690 return p.emitError(p.getCurrentLocation(), "Expected !
hw.array type
");
1692 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1693 idxType = IntegerType::get(p.getBuilder().getContext(), idxWidth);
1697static void printSliceTypes(OpAsmPrinter &p, Operation *, Type srcType,
1699 p.printType(srcType);
1702ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
1703 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
1704 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
1707 if (parser.parseOperandList(operands) ||
1708 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
1709 parser.parseType(elemType))
1712 if (operands.size() == 0)
1713 return parser.emitError(inputOperandsLoc,
1714 "Cannot construct an array of length 0
");
1716 // Check for optional result type: " -> <type>
"
1718 if (parser.parseOptionalArrow().succeeded()) {
1719 if (parser.parseType(resultType))
1721 result.addTypes(resultType);
1723 result.addTypes({ArrayType::get(elemType, operands.size())});
1726 for (auto operand : operands)
1727 if (parser.resolveOperand(operand, elemType, result.operands))
1732void ArrayCreateOp::print(OpAsmPrinter &p) {
1734 p.printOperands(getInputs());
1735 p.printOptionalAttrDict((*this)->getAttrs());
1736 p << " :
" << getInputs()[0].getType();
1738 // Print optional result type if it's not the default constructed type
1740 ArrayType::get(getInputs()[0].getType(), getInputs().size());
1741 if (getType() != expectedType)
1742 p << " ->
" << getType();
1745void ArrayCreateOp::build(OpBuilder &b, OperationState &state,
1746 ValueRange values) {
1747 assert(values.size() > 0 && "Cannot build array of zero elements
");
1748 Type elemType = values[0].getType();
1749 assert(llvm::all_of(
1751 [elemType](Value v) -> bool { return v.getType() == elemType; }) &&
1752 "All values must have same type.
");
1753 build(b, state, ArrayType::get(elemType, values.size()), values);
1756LogicalResult ArrayCreateOp::verify() {
1757 unsigned returnSize = hw::type_cast<ArrayType>(getType()).getNumElements();
1758 if (getInputs().size() != returnSize)
1763OpFoldResult ArrayCreateOp::fold(FoldAdaptor adaptor) {
1764 if (llvm::any_of(adaptor.getInputs(), [](Attribute attr) {
1765 return !isa_and_nonnull<IntegerAttr>(attr);
1768 return ArrayAttr::get(getContext(), adaptor.getInputs());
1771// Check whether an integer value is an offset from a base.
1772bool hw::isOffset(Value base, Value index, uint64_t offset) {
1773 if (auto constBase = base.getDefiningOp<hw::ConstantOp>()) {
1774 if (auto constIndex = index.getDefiningOp<hw::ConstantOp>()) {
1775 // If both values are a constant, check if index == base + offset.
1776 // To account for overflow, the addition is performed with an extra bit
1777 // and the offset is asserted to fit in the bit width of the base.
1778 auto baseValue = constBase.getValue();
1779 auto indexValue = constIndex.getValue();
1781 unsigned bits = baseValue.getBitWidth();
1782 assert(bits == indexValue.getBitWidth() && "mismatched widths
");
1784 if (bits < 64 && offset >= (1ull << bits))
1787 APInt baseExt = baseValue.zextOrTrunc(bits + 1);
1788 APInt indexExt = indexValue.zextOrTrunc(bits + 1);
1789 return baseExt + offset == indexExt;
1795// Canonicalize a create of consecutive elements to a slice.
1796static LogicalResult foldCreateToSlice(ArrayCreateOp op,
1797 PatternRewriter &rewriter) {
1798 // Do not canonicalize create of get into a slice.
1799 auto arrayTy = hw::type_cast<ArrayType>(op.getType());
1800 if (arrayTy.getNumElements() <= 1)
1802 auto elemTy = arrayTy.getElementType();
1804 // Check if create arguments are consecutive elements of the same array.
1805 // Attempt to break a create of gets into a sequence of consecutive intervals.
1811 SmallVector<Chunk> chunks;
1812 for (Value value : llvm::reverse(op.getInputs())) {
1813 auto get = value.getDefiningOp<ArrayGetOp>();
1817 Value input = get.getInput();
1818 Value index = get.getIndex();
1819 if (!chunks.empty()) {
1820 auto &c = *chunks.rbegin();
1821 if (c.input == get.getInput() && isOffset(c.index, index, c.size)) {
1827 chunks.push_back(Chunk{input, index, 1});
1830 // If there is a single slice, eliminate the create.
1831 if (chunks.size() == 1) {
1832 auto &chunk = chunks[0];
1833 rewriter.replaceOp(op, rewriter.createOrFold<ArraySliceOp>(
1834 op.getLoc(), arrayTy, chunk.input, chunk.index));
1838 // If the number of chunks is significantly less than the number of
1839 // elements, replace the create with a concat of the identified slices.
1840 if (chunks.size() * 2 < arrayTy.getNumElements()) {
1841 SmallVector<Value> slices;
1842 for (auto &chunk : llvm::reverse(chunks)) {
1843 auto sliceTy = ArrayType::get(elemTy, chunk.size);
1844 slices.push_back(rewriter.createOrFold<ArraySliceOp>(
1845 op.getLoc(), sliceTy, chunk.input, chunk.index));
1847 rewriter.replaceOpWithNewOp<ArrayConcatOp>(op, arrayTy, slices);
1854LogicalResult ArrayCreateOp::canonicalize(ArrayCreateOp op,
1855 PatternRewriter &rewriter) {
1856 if (succeeded(foldCreateToSlice(op, rewriter)))
1861Value ArrayCreateOp::getUniformElement() {
1862 if (!getInputs().empty() && llvm::all_equal(getInputs()))
1863 return getInputs()[0];
1867static std::optional<uint64_t> getUIntFromValue(Value value) {
1868 auto idxOp = dyn_cast_or_null<ConstantOp>(value.getDefiningOp());
1870 return std::nullopt;
1871 APInt idxAttr = idxOp.getValue();
1872 if (idxAttr.getBitWidth() > 64)
1873 return std::nullopt;
1874 return idxAttr.getLimitedValue();
1877LogicalResult ArraySliceOp::verify() {
1878 unsigned inputSize =
1879 type_cast<ArrayType>(getInput().getType()).getNumElements();
1880 if (llvm::Log2_64_Ceil(inputSize) !=
1881 getLowIndex().getType().getIntOrFloatBitWidth())
1883 "ArraySlice: index width must match clog2 of array size
");
1887OpFoldResult ArraySliceOp::fold(FoldAdaptor adaptor) {
1888 // If we are slicing the entire input, then return it.
1889 if (getType() == getInput().getType())
1894LogicalResult ArraySliceOp::canonicalize(ArraySliceOp op,
1895 PatternRewriter &rewriter) {
1896 auto sliceTy = hw::type_cast<ArrayType>(op.getType());
1897 auto elemTy = sliceTy.getElementType();
1898 uint64_t sliceSize = sliceTy.getNumElements();
1902 if (sliceSize == 1) {
1903 // slice(a, n) -> create(a[n])
1904 auto get = ArrayGetOp::create(rewriter, op.getLoc(), op.getInput(),
1906 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(),
1911 auto offsetOpt = getUIntFromValue(op.getLowIndex());
1915 auto *inputOp = op.getInput().getDefiningOp();
1916 if (auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
1917 // slice(slice(a, n), m) -> slice(a, n + m)
1918 if (inputSlice == op)
1921 auto inputIndex = inputSlice.getLowIndex();
1922 auto inputOffsetOpt = getUIntFromValue(inputIndex);
1923 if (!inputOffsetOpt)
1926 uint64_t offset = *offsetOpt + *inputOffsetOpt;
1928 ConstantOp::create(rewriter, op.getLoc(), inputIndex.getType(), offset);
1929 rewriter.replaceOpWithNewOp<ArraySliceOp>(op, op.getType(),
1930 inputSlice.getInput(), lowIndex);
1934 if (auto inputCreate = dyn_cast_or_null<ArrayCreateOp>(inputOp)) {
1935 // slice(create(a0, a1, ..., an), m) -> create(am, ...)
1936 auto inputs = inputCreate.getInputs();
1938 uint64_t begin = inputs.size() - *offsetOpt - sliceSize;
1939 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(),
1940 inputs.slice(begin, sliceSize));
1944 if (auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
1945 // slice(concat(a1, a2, ...)) -> concat(a2, slice(a3, ..), ...)
1946 SmallVector<Value> chunks;
1947 uint64_t sliceStart = *offsetOpt;
1948 for (auto input : llvm::reverse(inputConcat.getInputs())) {
1949 // Check whether the input intersects with the slice.
1950 uint64_t inputSize =
1951 hw::type_cast<ArrayType>(input.getType()).getNumElements();
1952 if (inputSize == 0 || inputSize <= sliceStart) {
1953 sliceStart -= inputSize;
1957 // Find the indices to slice from this input by intersection.
1958 uint64_t cutEnd = std::min(inputSize, sliceStart + sliceSize);
1959 uint64_t cutSize = cutEnd - sliceStart;
1960 assert(cutSize != 0 && "slice cannot be
empty");
1962 if (cutSize == inputSize) {
1963 // The whole input fits in the slice, add it.
1964 assert(sliceStart == 0 && "invalid cut size
");
1965 chunks.push_back(input);
1967 // Slice the required bits from the input.
1968 unsigned width = inputSize == 1 ? 1 : llvm::Log2_64_Ceil(inputSize);
1969 auto lowIndex = ConstantOp::create(
1970 rewriter, op.getLoc(), rewriter.getIntegerType(width), sliceStart);
1971 chunks.push_back(ArraySliceOp::create(
1972 rewriter, op.getLoc(), hw::ArrayType::get(elemTy, cutSize), input,
1977 sliceSize -= cutSize;
1982 assert(chunks.size() > 0 && "missing sliced items
");
1983 if (chunks.size() == 1)
1984 rewriter.replaceOp(op, chunks[0]);
1986 rewriter.replaceOpWithNewOp<ArrayConcatOp>(
1987 op, llvm::to_vector(llvm::reverse(chunks)));
1993//===----------------------------------------------------------------------===//
1995//===----------------------------------------------------------------------===//
1997static ParseResult parseArrayConcatTypes(OpAsmParser &p,
1998 SmallVectorImpl<Type> &inputTypes,
2001 uint64_t resultSize = 0;
2003 auto parseElement = [&]() -> ParseResult {
2005 if (p.parseType(ty))
2007 auto arrTy = type_dyn_cast<ArrayType>(ty);
2009 return p.emitError(p.getCurrentLocation(), "Expected !
hw.array type
");
2010 if (elemType && elemType != arrTy.getElementType())
2011 return p.emitError(p.getCurrentLocation(), "Expected array element type
")
2014 elemType = arrTy.getElementType();
2015 inputTypes.push_back(ty);
2016 resultSize += arrTy.getNumElements();
2020 if (p.parseCommaSeparatedList(parseElement))
2023 resultType = ArrayType::get(elemType, resultSize);
2027static void printArrayConcatTypes(OpAsmPrinter &p, Operation *,
2028 TypeRange inputTypes, Type resultType) {
2029 llvm::interleaveComma(inputTypes, p, [&p](Type t) { p << t; });
2032void ArrayConcatOp::build(OpBuilder &b, OperationState &state,
2033 ValueRange values) {
2034 assert(!values.empty() && "Cannot build array of zero elements
");
2035 ArrayType arrayTy = cast<ArrayType>(values[0].getType());
2036 Type elemTy = arrayTy.getElementType();
2037 assert(llvm::all_of(values,
2038 [elemTy](Value v) -> bool {
2039 return isa<ArrayType>(v.getType()) &&
2040 cast<ArrayType>(v.getType()).getElementType() ==
2043 "All values must be of ArrayType with the same element type.
");
2045 uint64_t resultSize = 0;
2046 for (Value val : values)
2047 resultSize += cast<ArrayType>(val.getType()).getNumElements();
2048 build(b, state, ArrayType::get(elemTy, resultSize), values);
2051OpFoldResult ArrayConcatOp::fold(FoldAdaptor adaptor) {
2052 if (getInputs().size() == 1)
2053 return getInputs()[0];
2055 auto inputs = adaptor.getInputs();
2056 SmallVector<Attribute> array;
2057 for (size_t i = 0, e = getNumOperands(); i < e; ++i) {
2060 llvm::copy(cast<ArrayAttr>(inputs[i]), std::back_inserter(array));
2062 return ArrayAttr::get(getContext(), array);
2065// Flatten a concatenation of array creates into a single create.
2066static bool flattenConcatOp(ArrayConcatOp op, PatternRewriter &rewriter) {
2067 for (auto input : op.getInputs())
2068 if (!input.getDefiningOp<ArrayCreateOp>())
2071 SmallVector<Value> items;
2072 for (auto input : op.getInputs()) {
2073 auto create = cast<ArrayCreateOp>(input.getDefiningOp());
2074 for (auto item : create.getInputs())
2075 items.push_back(item);
2078 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, items);
2082// Merge consecutive slice expressions in a concatenation.
2083static bool mergeConcatSlices(ArrayConcatOp op, PatternRewriter &rewriter) {
2089 SmallVector<Location> locs;
2092 SmallVector<Value> items;
2093 std::optional<Slice> last;
2094 bool changed = false;
2096 auto concatenate = [&] {
2097 // If there is only one op in the slice, place it to the items list.
2101 items.push_back(last->op);
2106 // Otherwise, create a new slice of with the given size and place it.
2107 // In this case, the concat op is replaced, using the new argument.
2109 auto loc = FusedLoc::get(op.getContext(), last->locs);
2110 auto origTy = hw::type_cast<ArrayType>(last->input.getType());
2111 auto arrayTy = ArrayType::get(origTy.getElementType(), last->size);
2112 items.push_back(rewriter.createOrFold<ArraySliceOp>(
2113 loc, arrayTy, last->input, last->index));
2118 auto append = [&](Value op, Value input, Value index, size_t size) {
2119 // If this slice is an extension of the previous one, extend the size
2120 // saved. In this case, a new slice of is created and the concatenation
2121 // operator is rewritten. Otherwise, flush the last slice.
2123 if (last->input == input && isOffset(last->index, index, last->size)) {
2126 last->locs.push_back(op.getLoc());
2131 last.emplace(Slice{input, index, size, op, {op.getLoc()}});
2134 for (auto item : llvm::reverse(op.getInputs())) {
2135 if (auto slice = item.getDefiningOp<ArraySliceOp>()) {
2136 auto size = hw::type_cast<ArrayType>(slice.getType()).getNumElements();
2137 append(item, slice.getInput(), slice.getLowIndex(), size);
2141 if (auto create = item.getDefiningOp<ArrayCreateOp>()) {
2142 if (create.getInputs().size() == 1) {
2143 if (auto get = create.getInputs()[0].getDefiningOp<ArrayGetOp>()) {
2144 append(item, get.getInput(), get.getIndex(), 1);
2151 items.push_back(item);
2158 if (items.size() == 1) {
2159 rewriter.replaceOp(op, items[0]);
2161 std::reverse(items.begin(), items.end());
2162 rewriter.replaceOpWithNewOp<ArrayConcatOp>(op, items);
2167LogicalResult ArrayConcatOp::canonicalize(ArrayConcatOp op,
2168 PatternRewriter &rewriter) {
2169 // concat(create(a1, ...), create(a3, ...), ...) -> create(a1, ..., a3, ...)
2170 if (flattenConcatOp(op, rewriter))
2173 // concat(slice(a, n, m), slice(a, n + m, p)) -> concat(slice(a, n, m + p))
2174 if (mergeConcatSlices(op, rewriter))
2180//===----------------------------------------------------------------------===//
2182//===----------------------------------------------------------------------===//
2184ParseResult EnumConstantOp::parse(OpAsmParser &parser, OperationState &result) {
2185 // Parse a Type instead of an EnumType since the type might be a type alias.
2186 // The validity of the canonical type is checked during construction of the
2191 auto loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());
2192 if (parser.parseKeyword(&field) || parser.parseColonType(type))
2195 auto fieldAttr = EnumFieldAttr::get(
2196 loc, StringAttr::get(parser.getContext(), field), type);
2201 result.addAttribute("field
", fieldAttr);
2202 result.addTypes(type);
2207void EnumConstantOp::print(OpAsmPrinter &p) {
2208 p << " " << getField().getField().getValue() << " :
"
2209 << getField().getType().getValue();
2212void EnumConstantOp::getAsmResultNames(
2213 function_ref<void(Value, StringRef)> setNameFn) {
2214 setNameFn(getResult(), getField().getField().str());
2217void EnumConstantOp::build(OpBuilder &builder, OperationState &odsState,
2218 EnumFieldAttr field) {
2219 return build(builder, odsState, field.getType().getValue(), field);
2222OpFoldResult EnumConstantOp::fold(FoldAdaptor adaptor) {
2223 assert(adaptor.getOperands().empty() && "constant has no operands
");
2224 return getFieldAttr();
2227LogicalResult EnumConstantOp::verify() {
2228 auto fieldAttr = getFieldAttr();
2229 auto fieldType = fieldAttr.getType().getValue();
2230 // This check ensures that we are using the exact same type, without looking
2231 // through type aliases.
2232 if (fieldType != getType())
2233 emitOpError("return type
")
2234 << getType() << " does not match attribute type
" << fieldAttr;
2238//===----------------------------------------------------------------------===//
2240//===----------------------------------------------------------------------===//
2242LogicalResult EnumCmpOp::verify() {
2243 // Compare the canonical types.
2244 auto lhsType = type_cast<EnumType>(getLhs().getType());
2245 auto rhsType = type_cast<EnumType>(getRhs().getType());
2246 if (rhsType != lhsType)
2247 emitOpError("types
do not match
");
2251//===----------------------------------------------------------------------===//
2253//===----------------------------------------------------------------------===//
2255ParseResult StructCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2256 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2257 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
2258 Type declOrAliasType;
2260 if (parser.parseLParen() || parser.parseOperandList(operands) ||
2261 parser.parseRParen() || parser.parseOptionalAttrDict(result.attributes) ||
2262 parser.parseColonType(declOrAliasType))
2265 auto declType = type_dyn_cast<StructType>(declOrAliasType);
2267 return parser.emitError(parser.getNameLoc(),
2268 "expected !
hw.struct type or alias
");
2270 llvm::SmallVector<Type, 4> structInnerTypes;
2271 declType.getInnerTypes(structInnerTypes);
2272 result.addTypes(declOrAliasType);
2274 if (parser.resolveOperands(operands, structInnerTypes, inputOperandsLoc,
2280void StructCreateOp::print(OpAsmPrinter &printer) {
2282 printer.printOperands(getInput());
2284 printer.printOptionalAttrDict((*this)->getAttrs());
2285 printer << " :
" << getType();
2288LogicalResult StructCreateOp::verify() {
2289 auto elements = hw::type_cast<StructType>(getType()).getElements();
2291 if (elements.size() != getInput().size())
2292 return emitOpError("structure field count mismatch
");
2294 for (const auto &[field, value] : llvm::zip(elements, getInput()))
2295 if (field.type != value.getType())
2296 return emitOpError("structure field `
")
2297 << field.name << "` type does not match
";
2302OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
2303 // struct_create(struct_explode(x)) => x
2304 if (!getInput().empty())
2305 if (auto explodeOp = getInput()[0].getDefiningOp<StructExplodeOp>();
2306 explodeOp && getInput() == explodeOp.getResults() &&
2307 getResult().getType() == explodeOp.getInput().getType())
2308 return explodeOp.getInput();
2310 auto inputs = adaptor.getInput();
2311 if (llvm::any_of(inputs, [](Attribute attr) {
2312 return !isa_and_nonnull<IntegerAttr>(attr);
2315 return ArrayAttr::get(getContext(), inputs);
2318LogicalResult StructCreateOp::canonicalize(StructCreateOp op,
2319 PatternRewriter &rewriter) {
2320 // Fold away a struct_create whose inputs are struct_extract ops that
2321 // reconstruct the same struct in field order from a single source value.
2323 for (auto [i, operand] : llvm::enumerate(op.getInput())) {
2324 auto extractOp = operand.getDefiningOp<StructExtractOp>();
2325 if (!extractOp || extractOp.getFieldIndex() != i ||
2326 extractOp.getInput().getType() != op.getType()) {
2331 foldVal = extractOp.getInput();
2332 } else if (extractOp.getInput() != foldVal) {
2337 if (foldVal && foldVal != op.getResult()) {
2338 rewriter.replaceOp(op, foldVal);
2344//===----------------------------------------------------------------------===//
2346//===----------------------------------------------------------------------===//
2348ParseResult StructExplodeOp::parse(OpAsmParser &parser,
2349 OperationState &result) {
2350 OpAsmParser::UnresolvedOperand operand;
2353 if (parser.parseOperand(operand) ||
2354 parser.parseOptionalAttrDict(result.attributes) ||
2355 parser.parseColonType(declType))
2357 auto structType = type_dyn_cast<StructType>(declType);
2359 return parser.emitError(parser.getNameLoc(),
2360 "invalid kind of type specified
");
2362 llvm::SmallVector<Type, 4> structInnerTypes;
2363 structType.getInnerTypes(structInnerTypes);
2364 result.addTypes(structInnerTypes);
2366 if (parser.resolveOperand(operand, declType, result.operands))
2371void StructExplodeOp::print(OpAsmPrinter &printer) {
2373 printer.printOperand(getInput());
2374 printer.printOptionalAttrDict((*this)->getAttrs());
2375 printer << " :
" << getInput().getType();
2378LogicalResult StructExplodeOp::fold(FoldAdaptor adaptor,
2379 SmallVectorImpl<OpFoldResult> &results) {
2380 auto input = adaptor.getInput();
2383 llvm::copy(cast<ArrayAttr>(input), std::back_inserter(results));
2387LogicalResult StructExplodeOp::canonicalize(StructExplodeOp op,
2388 PatternRewriter &rewriter) {
2389 auto *inputOp = op.getInput().getDefiningOp();
2390 auto elements = type_cast<StructType>(op.getInput().getType()).getElements();
2391 auto result = failure();
2392 auto opResults = op.getResults();
2393 for (uint32_t index = 0; index < elements.size(); index++) {
2394 if (auto foldResult = foldStructExtract(inputOp, index)) {
2395 rewriter.replaceAllUsesWith(opResults[index], foldResult);
2402void StructExplodeOp::getAsmResultNames(
2403 function_ref<void(Value, StringRef)> setNameFn) {
2404 auto structType = type_cast<StructType>(getInput().getType());
2405 for (auto [res, field] : llvm::zip(getResults(), structType.getElements()))
2406 setNameFn(res, field.name.str());
2409void StructExplodeOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2411 StructType inputType = dyn_cast<StructType>(input.getType());
2413 SmallVector<Type, 16> fieldTypes;
2414 for (auto field : inputType.getElements())
2415 fieldTypes.push_back(field.type);
2416 build(odsBuilder, odsState, fieldTypes, input);
2419//===----------------------------------------------------------------------===//
2421//===----------------------------------------------------------------------===//
2425template <typename AggregateOp, typename AggregateType>
2426static LogicalResult verifyAggregateFieldIndexAndType(AggregateOp &op,
2427 AggregateType aggType,
2429 auto index = op.getFieldIndex();
2430 if (index >= aggType.getElements().size())
2431 return op.emitOpError() << "field index
" << index
2432 << " exceeds element count of aggregate type
";
2434 if (getCanonicalType(elementType) !=
2435 getCanonicalType(aggType.getElements()[index].type))
2436 return op.emitOpError()
2437 << "type
" << aggType.getElements()[index].type
2438 << " of accessed field in aggregate at index
" << index
2439 << " does not match expected type
" << elementType;
2444LogicalResult StructExtractOp::verify() {
2445 return verifyAggregateFieldIndexAndType<StructExtractOp, StructType>(
2446 *this, getInput().getType(), getType());
2451template <typename AggregateType>
2452static ParseResult parseExtractOp(OpAsmParser &parser, OperationState &result) {
2453 OpAsmParser::UnresolvedOperand operand;
2454 StringAttr fieldName;
2457 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2458 parser.parseAttribute(fieldName) || parser.parseRSquare() ||
2459 parser.parseOptionalAttrDict(result.attributes) ||
2460 parser.parseColonType(declType))
2462 auto aggType = type_dyn_cast<AggregateType>(declType);
2464 return parser.emitError(parser.getNameLoc(),
2465 "invalid kind of type specified
");
2467 auto fieldIndex = aggType.getFieldIndex(fieldName);
2469 parser.emitError(parser.getNameLoc(), "field name
'" +
2470 fieldName.getValue() +
2471 "' not
found in aggregate type
");
2476 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2477 result.addAttribute("fieldIndex
", indexAttr);
2478 Type resultType = aggType.getElements()[*fieldIndex].type;
2479 result.addTypes(resultType);
2481 if (parser.resolveOperand(operand, declType, result.operands))
2488template <typename AggType>
2489static void printExtractOp(OpAsmPrinter &printer, AggType op) {
2491 printer.printOperand(op.getInput());
2493 printer.printOptionalAttrDict(op->getAttrs(), {
"fieldIndex"});
2494 printer <<
" : " << op.getInput().getType();
2497ParseResult StructExtractOp::parse(OpAsmParser &parser,
2498 OperationState &result) {
2502void StructExtractOp::print(OpAsmPrinter &printer) {
2506void StructExtractOp::build(OpBuilder &builder, OperationState &odsState,
2507 Value input, StructType::FieldInfo field) {
2510 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2511 build(builder, odsState, field.type, input, *fieldIndex);
2514void StructExtractOp::build(OpBuilder &builder, OperationState &odsState,
2515 Value input, StringAttr fieldName) {
2517 auto fieldIndex = structType.getFieldIndex(fieldName);
2518 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2519 auto resultType = structType.getElements()[*fieldIndex].type;
2520 build(builder, odsState, resultType, input, *fieldIndex);
2523OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
2524 if (
auto constOperand = adaptor.getInput()) {
2526 auto operandAttr = llvm::cast<ArrayAttr>(constOperand);
2527 return operandAttr.getValue()[getFieldIndex()];
2530 if (
auto foldResult =
2536LogicalResult StructExtractOp::canonicalize(StructExtractOp op,
2537 PatternRewriter &rewriter) {
2538 auto *inputOp = op.getInput().getDefiningOp();
2541 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
2542 if (structInject.getFieldIndex() != op.getFieldIndex()) {
2543 rewriter.replaceOpWithNewOp<StructExtractOp>(
2544 op, op.getType(), structInject.getInput(), op.getFieldIndexAttr());
2552void StructExtractOp::getAsmResultNames(
2553 function_ref<
void(Value, StringRef)> setNameFn) {
2561void StructInjectOp::build(OpBuilder &builder, OperationState &odsState,
2562 Value input, StringAttr fieldName, Value newValue) {
2564 auto fieldIndex = structType.getFieldIndex(fieldName);
2565 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2566 build(builder, odsState, input, *fieldIndex, newValue);
2569LogicalResult StructInjectOp::verify() {
2571 *
this, getInput().getType(), getNewValue().getType());
2574ParseResult StructInjectOp::parse(OpAsmParser &parser, OperationState &result) {
2575 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2576 OpAsmParser::UnresolvedOperand operand, val;
2577 StringAttr fieldName;
2580 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2581 parser.parseAttribute(fieldName) || parser.parseRSquare() ||
2582 parser.parseComma() || parser.parseOperand(val) ||
2583 parser.parseOptionalAttrDict(result.attributes) ||
2584 parser.parseColonType(declType))
2588 return parser.emitError(inputOperandsLoc,
"invalid kind of type specified");
2590 auto fieldIndex = structType.getFieldIndex(fieldName);
2592 parser.emitError(parser.getNameLoc(),
"field name '" +
2593 fieldName.getValue() +
2594 "' not found in aggregate type");
2599 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2600 result.addAttribute(
"fieldIndex", indexAttr);
2601 result.addTypes(declType);
2603 Type resultType = structType.getElements()[*fieldIndex].type;
2604 if (parser.resolveOperands({operand, val}, {declType, resultType},
2605 inputOperandsLoc, result.operands))
2610void StructInjectOp::print(OpAsmPrinter &printer) {
2612 printer.printOperand(getInput());
2614 printer.printOperand(getNewValue());
2615 printer.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
2616 printer <<
" : " << getInput().getType();
2619OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
2620 auto input = adaptor.getInput();
2621 auto newValue = adaptor.getNewValue();
2622 if (!input || !newValue)
2624 SmallVector<Attribute> array;
2625 llvm::copy(cast<ArrayAttr>(input), std::back_inserter(array));
2626 array[getFieldIndex()] = newValue;
2627 return ArrayAttr::get(getContext(), array);
2630LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
2631 PatternRewriter &rewriter) {
2635 if (op->hasOneUse()) {
2636 auto &use = *op->use_begin();
2637 if (isa<StructInjectOp>(use.getOwner()) && use.getOperandNumber() == 0)
2642 SmallPtrSet<Operation *, 4> injects;
2643 DenseMap<StringAttr, Value> fields;
2646 StructInjectOp inject = op;
2649 if (!injects.insert(inject).second)
2652 fields.try_emplace(inject.getFieldNameAttr(), inject.getNewValue());
2653 input = inject.getInput();
2654 inject = dyn_cast_or_null<StructInjectOp>(input.getDefiningOp());
2656 assert(input &&
"missing input to inject chain");
2659 auto elements = ty.getElements();
2662 if (fields.size() == elements.size()) {
2663 SmallVector<Value> createFields;
2664 for (
const auto &field : elements) {
2665 auto it = fields.find(field.name);
2666 assert(it != fields.end() &&
"missing field");
2667 createFields.push_back(it->second);
2669 rewriter.replaceOpWithNewOp<StructCreateOp>(op, ty, createFields);
2674 if (injects.size() == fields.size())
2678 for (uint32_t fieldIndex = 0; fieldIndex < elements.size(); fieldIndex++) {
2679 auto it = fields.find(elements[fieldIndex].name);
2680 if (it == fields.end())
2682 input = StructInjectOp::create(rewriter, op.getLoc(), ty, input, fieldIndex,
2686 rewriter.replaceOp(op, input);
2694LogicalResult UnionCreateOp::verify() {
2696 *
this, getType(), getInput().getType());
2699void UnionCreateOp::build(OpBuilder &builder, OperationState &odsState,
2700 Type unionType, StringAttr fieldName, Value input) {
2702 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2703 build(builder, odsState, unionType, *fieldIndex, input);
2706ParseResult UnionCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2707 Type declOrAliasType;
2708 StringAttr fieldName;
2709 OpAsmParser::UnresolvedOperand input;
2710 llvm::SMLoc fieldLoc = parser.getCurrentLocation();
2712 if (parser.parseAttribute(fieldName) || parser.parseComma() ||
2713 parser.parseOperand(input) ||
2714 parser.parseOptionalAttrDict(result.attributes) ||
2715 parser.parseColonType(declOrAliasType))
2720 return parser.emitError(parser.getNameLoc(),
2721 "expected !hw.union type or alias");
2723 auto fieldIndex = declType.getFieldIndex(fieldName);
2725 parser.emitError(fieldLoc,
"cannot find union field '")
2726 << fieldName.getValue() <<
'\'';
2731 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2732 result.addAttribute(
"fieldIndex", indexAttr);
2733 Type inputType = declType.getElements()[*fieldIndex].type;
2735 if (parser.resolveOperand(input, inputType, result.operands))
2737 result.addTypes({declOrAliasType});
2741void UnionCreateOp::print(OpAsmPrinter &printer) {
2743 printer.printOperand(getInput());
2744 printer.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
2745 printer <<
" : " << getType();
2752ParseResult UnionExtractOp::parse(OpAsmParser &parser, OperationState &result) {
2756void UnionExtractOp::print(OpAsmPrinter &printer) {
2760LogicalResult UnionExtractOp::inferReturnTypes(
2761 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
2762 DictionaryAttr
attrs, mlir::PropertyRef properties,
2763 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2764 Adaptor adaptor(operands,
attrs, properties, regions);
2765 auto unionElements =
2767 unsigned fieldIndex = adaptor.getFieldIndexAttr().getValue().getZExtValue();
2768 if (fieldIndex >= unionElements.size()) {
2770 mlir::emitError(*loc,
"field index " + Twine(fieldIndex) +
2771 " exceeds element count of aggregate type");
2774 results.push_back(unionElements[fieldIndex].type);
2778void UnionExtractOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2779 Value input, StringAttr fieldName) {
2781 auto fieldIndex = unionType.getFieldIndex(fieldName);
2782 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2783 auto resultType = unionType.getElements()[*fieldIndex].type;
2784 build(odsBuilder, odsState, resultType, input, *fieldIndex);
2787LogicalResult UnionExtractOp::canonicalize(UnionExtractOp extractOp,
2788 PatternRewriter &rewriter) {
2791 if (
auto createOp = extractOp.getInput().getDefiningOp<UnionCreateOp>()) {
2792 if (createOp.getInput().getType() == extractOp.getType() &&
2793 createOp.getInput() != extractOp.getResult()) {
2794 auto unionTypeElts =
2795 cast<UnionType>(extractOp.getInput().getType()).getElements();
2796 if (unionTypeElts[createOp.getFieldIndex()].offset ==
2797 unionTypeElts[extractOp.getFieldIndex()].offset) {
2798 rewriter.replaceOp(extractOp, createOp.getInput());
2804 if (
auto bitcastOp = extractOp.getInput().getDefiningOp<BitcastOp>()) {
2805 auto inputWidth =
getBitWidth(bitcastOp.getInput().getType());
2806 assert(inputWidth >= 0 &&
2807 inputWidth ==
getBitWidth(extractOp.getInput().getType()) &&
2808 "bitcast does not cover entire union");
2809 if (inputWidth ==
getBitWidth(extractOp.getType())) {
2810 auto loc = FusedLoc::get(rewriter.getContext(),
2811 {bitcastOp.getLoc(), extractOp.getLoc()});
2812 auto newBitcast = rewriter.createOrFold<BitcastOp>(
2813 loc, extractOp.getType(), bitcastOp.getInput());
2814 rewriter.replaceOp(extractOp, newBitcast);
2831OpFoldResult ArrayGetOp::fold(FoldAdaptor adaptor) {
2832 auto inputCst = dyn_cast_or_null<ArrayAttr>(adaptor.getInput());
2833 auto indexCst = dyn_cast_or_null<IntegerAttr>(adaptor.getIndex());
2838 auto indexVal = indexCst.getValue();
2839 if (indexVal.getBitWidth() < 64) {
2840 auto index = indexVal.getZExtValue();
2844 if (index >= inputCst.size())
2846 return inputCst[inputCst.size() - 1 - index];
2851 if (!inputCst.empty() && llvm::all_equal(inputCst))
2856 if (
auto bitcast = getInput().getDefiningOp<hw::BitcastOp>()) {
2857 auto intTy = dyn_cast<IntegerType>(getType());
2860 auto bitcastInputOp = bitcast.getInput().getDefiningOp<hw::ConstantOp>();
2861 if (!bitcastInputOp)
2865 auto bitcastInputCst = bitcastInputOp.getValue();
2868 auto startIdx = indexCst.getValue().zext(bitcastInputCst.getBitWidth()) *
2869 getType().getIntOrFloatBitWidth();
2871 return IntegerAttr::get(intTy, bitcastInputCst.lshr(startIdx).trunc(
2872 intTy.getIntOrFloatBitWidth()));
2876 if (
auto inject = getInput().getDefiningOp<ArrayInjectOp>())
2877 if (getIndex() == inject.getIndex())
2878 return inject.getElement();
2880 auto inputCreate = getInput().getDefiningOp<ArrayCreateOp>();
2884 if (
auto uniformValue = inputCreate.getUniformElement())
2885 return uniformValue;
2887 if (!indexCst || indexCst.getValue().getBitWidth() > 64)
2890 uint64_t index = indexCst.getValue().getLimitedValue();
2891 auto createInputs = inputCreate.getInputs();
2892 if (index >= createInputs.size())
2894 return createInputs[createInputs.size() - index - 1];
2897LogicalResult ArrayGetOp::canonicalize(ArrayGetOp op,
2898 PatternRewriter &rewriter) {
2903 auto *inputOp = op.getInput().getDefiningOp();
2904 if (
auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
2906 auto offsetOp = inputSlice.getLowIndex();
2911 uint64_t offset = *offsetOpt + *idxOpt;
2914 rewriter.replaceOpWithNewOp<ArrayGetOp>(op, inputSlice.getInput(),
2919 if (
auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
2921 uint64_t elemIndex = *idxOpt;
2922 for (
auto input : llvm::reverse(inputConcat.getInputs())) {
2924 if (elemIndex >= size) {
2929 unsigned indexWidth = size == 1 ? 1 : llvm::Log2_64_Ceil(size);
2932 rewriter.getIntegerType(indexWidth), elemIndex);
2934 rewriter.replaceOpWithNewOp<ArrayGetOp>(op, input, newIdxOp);
2943 if (
auto innerGet = dyn_cast_or_null<hw::ArrayGetOp>(inputOp)) {
2944 if (!innerGet.getIndex().getDefiningOp<hw::ConstantOp>()) {
2946 innerGet.getInput().getDefiningOp<hw::ArrayCreateOp>()) {
2948 SmallVector<Value> newValues;
2949 for (
auto operand : create.getOperands())
2950 newValues.push_back(rewriter.createOrFold<hw::ArrayGetOp>(
2951 op.getLoc(), operand, op.getIndex()));
2953 rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(
2955 rewriter.createOrFold<hw::ArrayCreateOp>(op.getLoc(), newValues),
2956 innerGet.getIndex());
2969OpFoldResult ArrayInjectOp::fold(FoldAdaptor adaptor) {
2970 auto inputAttr = dyn_cast_or_null<ArrayAttr>(adaptor.getInput());
2971 auto indexAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getIndex());
2972 auto elementAttr = adaptor.getElement();
2975 if (inputAttr && indexAttr && elementAttr) {
2976 if (
auto index = indexAttr.getValue().tryZExtValue()) {
2977 if (*index < inputAttr.size()) {
2978 SmallVector<Attribute> elements(inputAttr.getValue());
2979 elements[inputAttr.size() - 1 - *index] = elementAttr;
2980 return ArrayAttr::get(getContext(), elements);
2989 PatternRewriter &rewriter) {
2993 if (op->hasOneUse()) {
2994 auto &use = *op->use_begin();
2995 if (isa<ArrayInjectOp>(use.getOwner()) && use.getOperandNumber() == 0)
3003 while (
auto inject = input.getDefiningOp<ArrayInjectOp>()) {
3006 if (!matchPattern(inject.getIndex(), mlir::m_ConstantInt(&indexAPInt)))
3008 if (indexAPInt.getActiveBits() > 32)
3010 uint32_t index = indexAPInt.getZExtValue();
3015 if (index < arrayLength)
3016 elements.insert({index, inject.getElement()});
3019 input = inject.getInput();
3026 if (elements.size() == arrayLength) {
3027 SmallVector<Value, 4> operands;
3028 operands.reserve(arrayLength);
3029 for (uint32_t idx = 0; idx < arrayLength; ++idx)
3030 operands.push_back(elements.at(arrayLength - idx - 1));
3031 rewriter.replaceOpWithNewOp<
ArrayCreateOp>(op, op.getType(), operands);
3040 auto createOp = op.getInput().getDefiningOp<
ArrayCreateOp>();
3046 if (!matchPattern(op.getIndex(), mlir::m_ConstantInt(&indexAPInt)) ||
3047 !indexAPInt.ult(createOp.getInputs().size()))
3051 SmallVector<Value> elements = createOp.getInputs();
3052 elements[elements.size() - indexAPInt.getZExtValue() - 1] = op.getElement();
3057void ArrayInjectOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
3059 patterns.add<ArrayInjectToSameIndex>(
context);
3068LogicalResult TypedeclOp::verify() {
3069 if (!isa_and_nonnull<hw::TypeScopeLike>(getOperation()->getParentOp()))
3070 return emitOpError(
"expects parent op to be a type scope, such as "
3071 "'hw.type_scope' or 'sv.package'");
3075StringRef TypedeclOp::getPreferredName() {
3076 return getVerilogName().value_or(
getName());
3079Type TypedeclOp::getAliasType() {
3080 auto parentScope = cast<hw::TypeScopeLike>(getOperation()->getParentOp());
3081 return hw::TypeAliasType::get(
3082 SymbolRefAttr::get(parentScope.getNameAttr(),
3083 {FlatSymbolRefAttr::get(*this)}),
3091OpFoldResult BitcastOp::fold(FoldAdaptor adaptor) {
3094 if (getOperand().getType() == getType())
3095 return getOperand();
3098 if (
auto intAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput())) {
3105 if (
auto arrayAttr = dyn_cast_or_null<ArrayAttr>(adaptor.getInput())) {
3109 if (
auto intType = dyn_cast<IntegerType>(getType()))
3110 return IntegerAttr::get(intType, intVal);
3120LogicalResult BitcastOp::canonicalize(BitcastOp op, PatternRewriter &rewriter) {
3126 dyn_cast_or_null<BitcastOp>(op.getInput().getDefiningOp());
3129 auto bitcast = rewriter.createOrFold<BitcastOp>(op.getLoc(), op.getType(),
3130 inputBitcast.getInput());
3131 rewriter.replaceOp(op, bitcast);
3135LogicalResult BitcastOp::verify() {
3137 return this->emitOpError(
"Bitwidth of input must match result");
3145bool HierPathOp::dropModule(StringAttr moduleToDrop) {
3146 SmallVector<Attribute, 4> newPath;
3147 bool updateMade =
false;
3148 for (
auto nameRef : getNamepath()) {
3150 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3151 if (ref.getModule() == moduleToDrop)
3154 newPath.push_back(ref);
3156 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == moduleToDrop)
3159 newPath.push_back(nameRef);
3163 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3167bool HierPathOp::inlineModule(StringAttr moduleToDrop) {
3168 SmallVector<Attribute, 4> newPath;
3169 bool updateMade =
false;
3170 StringRef inlinedInstanceName =
"";
3171 for (
auto nameRef : getNamepath()) {
3173 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3174 if (ref.getModule() == moduleToDrop) {
3175 inlinedInstanceName = ref.getName().getValue();
3177 }
else if (!inlinedInstanceName.empty()) {
3178 newPath.push_back(hw::InnerRefAttr::get(
3180 StringAttr::get(getContext(), inlinedInstanceName +
"_" +
3181 ref.getName().getValue())));
3182 inlinedInstanceName =
"";
3184 newPath.push_back(ref);
3186 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == moduleToDrop)
3189 newPath.push_back(nameRef);
3193 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3197bool HierPathOp::updateModule(StringAttr oldMod, StringAttr newMod) {
3198 SmallVector<Attribute, 4> newPath;
3199 bool updateMade =
false;
3200 for (
auto nameRef : getNamepath()) {
3202 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3203 if (ref.getModule() == oldMod) {
3204 newPath.push_back(hw::InnerRefAttr::get(newMod, ref.getName()));
3207 newPath.push_back(ref);
3209 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == oldMod) {
3210 newPath.push_back(FlatSymbolRefAttr::get(newMod));
3213 newPath.push_back(nameRef);
3217 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3221bool HierPathOp::updateModuleAndInnerRef(
3222 StringAttr oldMod, StringAttr newMod,
3223 const llvm::DenseMap<StringAttr, StringAttr> &innerSymRenameMap) {
3224 auto fromRef = FlatSymbolRefAttr::get(oldMod);
3225 if (oldMod == newMod)
3228 auto namepathNew = getNamepath().getValue().vec();
3229 bool updateMade =
false;
3231 for (
auto &element : namepathNew) {
3232 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(element)) {
3233 if (innerRef.getModule() != oldMod)
3235 auto symName = innerRef.getName();
3238 auto to = innerSymRenameMap.find(symName);
3239 if (to != innerSymRenameMap.end())
3240 symName = to->second;
3242 element = hw::InnerRefAttr::get(newMod, symName);
3245 if (element != fromRef)
3249 element = FlatSymbolRefAttr::get(newMod);
3253 setNamepathAttr(ArrayAttr::get(getContext(), namepathNew));
3257bool HierPathOp::truncateAtModule(StringAttr atMod,
bool includeMod) {
3258 SmallVector<Attribute, 4> newPath;
3259 bool updateMade =
false;
3260 for (
auto nameRef : getNamepath()) {
3262 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3263 if (ref.getModule() == atMod) {
3266 newPath.push_back(ref);
3268 newPath.push_back(ref);
3270 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == atMod && !includeMod)
3273 newPath.push_back(nameRef);
3279 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3284StringAttr HierPathOp::modPart(
unsigned i) {
3285 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3286 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
3287 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
3291StringAttr HierPathOp::root() {
3297bool HierPathOp::hasModule(StringAttr modName) {
3298 for (
auto nameRef : getNamepath()) {
3300 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3301 if (ref.getModule() == modName)
3304 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == modName)
3312bool HierPathOp::hasInnerSym(StringAttr modName, StringAttr symName)
const {
3313 for (
auto nameRef :
const_cast<HierPathOp *
>(
this)->getNamepath())
3314 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef))
3315 if (ref.getName() == symName && ref.getModule() == modName)
3323StringAttr HierPathOp::refPart(
unsigned i) {
3324 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3325 .Case<FlatSymbolRefAttr>([](
auto a) {
return StringAttr({}); })
3326 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getName(); });
3331StringAttr HierPathOp::ref() {
3333 return refPart(getNamepath().size() - 1);
3337StringAttr HierPathOp::leafMod() {
3339 return modPart(getNamepath().size() - 1);
3344bool HierPathOp::isModule() {
return !ref(); }
3348bool HierPathOp::isComponent() {
return (
bool)ref(); }
3363LogicalResult HierPathOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
3364 ArrayAttr expectedModuleNames = {};
3365 auto checkExpectedModule = [&](Attribute name) -> LogicalResult {
3366 if (!expectedModuleNames)
3368 if (llvm::any_of(expectedModuleNames,
3369 [name](Attribute attr) {
return attr == name; }))
3371 auto diag = emitOpError() <<
"instance path is incorrect. Expected ";
3372 size_t n = expectedModuleNames.size();
3376 for (
size_t i = 0; i < n; ++i) {
3378 diag << ((i + 1 == n) ?
" or " :
", ");
3379 diag << cast<StringAttr>(expectedModuleNames[i]);
3381 diag <<
". Instead found: " << name;
3385 if (!getNamepath() || getNamepath().
empty())
3386 return emitOpError() <<
"the instance path cannot be empty";
3387 for (
unsigned i = 0, s = getNamepath().size() - 1; i <
s; ++i) {
3388 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(getNamepath()[i]);
3390 return emitOpError()
3391 <<
"the instance path can only contain inner sym reference"
3392 <<
", only the leaf can refer to a module symbol";
3394 if (failed(checkExpectedModule(innerRef.getModule())))
3397 auto instOp = ns.
lookupOp<igraph::InstanceOpInterface>(innerRef);
3399 return emitOpError() <<
" module: " << innerRef.getModule()
3400 <<
" does not contain any instance with symbol: "
3401 << innerRef.getName();
3402 expectedModuleNames = instOp.getReferencedModuleNamesAttr();
3406 auto leafRef = getNamepath()[getNamepath().size() - 1];
3407 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(leafRef)) {
3408 if (!ns.
lookup(innerRef)) {
3409 return emitOpError() <<
" operation with symbol: " << innerRef
3410 <<
" was not found ";
3412 if (failed(checkExpectedModule(innerRef.getModule())))
3414 }
else if (failed(checkExpectedModule(
3415 cast<FlatSymbolRefAttr>(leafRef).getAttr()))) {
3421void HierPathOp::print(OpAsmPrinter &p) {
3425 StringRef visibilityAttrName =
3426 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
3427 if (
auto visibility =
3428 getOperation()->getAttrOfType<StringAttr>(visibilityAttrName))
3429 p << visibility.getValue() <<
' ';
3431 p.printSymbolName(getSymName());
3433 llvm::interleaveComma(getNamepath().getValue(), p, [&](Attribute attr) {
3434 if (
auto ref = dyn_cast<hw::InnerRefAttr>(attr)) {
3435 p.printSymbolName(ref.getModule().getValue());
3437 p.printSymbolName(ref.getName().getValue());
3439 p.printSymbolName(cast<FlatSymbolRefAttr>(attr).getValue());
3443 p.printOptionalAttrDict(
3444 (*this)->getAttrs(),
3445 {getSymNameAttrName(),
"namepath", visibilityAttrName});
3448ParseResult HierPathOp::parse(OpAsmParser &parser, OperationState &result) {
3450 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
3454 if (parser.parseSymbolName(symName, getSymNameAttrName(result.name),
3459 SmallVector<Attribute> namepath;
3460 if (parser.parseCommaSeparatedList(
3461 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
3462 auto loc = parser.getCurrentLocation();
3464 if (parser.parseAttribute(ref))
3468 auto pathLength = ref.getNestedReferences().size();
3469 if (pathLength == 0)
3471 FlatSymbolRefAttr::get(ref.getRootReference()));
3472 else if (pathLength == 1)
3473 namepath.push_back(hw::InnerRefAttr::get(ref.getRootReference(),
3474 ref.getLeafReference()));
3476 return parser.emitError(loc,
3477 "only one nested reference is allowed");
3481 result.addAttribute(
"namepath",
3482 ArrayAttr::get(parser.getContext(), namepath));
3484 if (parser.parseOptionalAttrDict(result.attributes))
3494void TriggeredOp::build(OpBuilder &builder, OperationState &odsState,
3495 EventControlAttr event, Value trigger,
3496 ValueRange inputs) {
3497 odsState.addOperands(trigger);
3498 odsState.addOperands(inputs);
3499 odsState.addAttribute(getEventAttrName(odsState.name), event);
3500 auto *r = odsState.addRegion();
3504 llvm::SmallVector<Location> argLocs;
3505 llvm::transform(inputs, std::back_inserter(argLocs),
3506 [&](Value v) {
return v.getLoc(); });
3507 b->addArguments(inputs.getTypes(), argLocs);
3515#define GET_OP_CLASSES
3516#include "circt/Dialect/HW/HW.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LogicalResult verifyModuleCommon(HWModuleLike module)
static void printParamValue(OpAsmPrinter &p, Operation *, Attribute value, Type resultType)
static LogicalResult canonicalizeArrayInjectChain(ArrayInjectOp op, PatternRewriter &rewriter)
static void printModuleOp(OpAsmPrinter &p, ModuleTy mod)
static ArrayAttr arrayOrEmpty(mlir::MLIRContext *context, ArrayRef< Attribute > attrs)
FunctionType getHWModuleOpType(Operation *op)
static void printExtractOp(OpAsmPrinter &printer, AggType op)
Use the same printer for both struct_extract and union_extract since the syntax is identical.
static void modifyModulePorts(Operation *op, ArrayRef< std::pair< unsigned, PortInfo > > insertInputs, ArrayRef< std::pair< unsigned, PortInfo > > insertOutputs, ArrayRef< unsigned > removeInputs, ArrayRef< unsigned > removeOutputs, Block *body=nullptr)
Insert and remove ports of a module.
static Value foldStructExtract(Operation *inputOp, uint32_t fieldIndex)
static bool hasAttribute(StringRef name, ArrayRef< NamedAttribute > attrs)
static void modifyModuleArgs(MLIRContext *context, ArrayRef< std::pair< unsigned, PortInfo > > insertArgs, ArrayRef< unsigned > removeArgs, ArrayRef< Attribute > oldArgNames, ArrayRef< Type > oldArgTypes, ArrayRef< Attribute > oldArgAttrs, ArrayRef< Location > oldArgLocs, SmallVector< Attribute > &newArgNames, SmallVector< Type > &newArgTypes, SmallVector< Attribute > &newArgAttrs, SmallVector< Location > &newArgLocs, Block *body=nullptr)
Internal implementation of argument/result insertion and removal on modules.
static ParseResult parseExtractOp(OpAsmParser &parser, OperationState &result)
Use the same parser for both struct_extract and union_extract since the syntax is identical.
static void getAsmBlockArgumentNamesImpl(mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static ParseResult parseParamValue(OpAsmParser &p, Attribute &value, Type &resultType)
static LogicalResult checkAttributes(Operation *op, Attribute attr, Type type)
static LogicalResult canonicalizeArrayInjectIntoCreate(ArrayInjectOp op, PatternRewriter &rewriter)
static std::optional< uint64_t > getUIntFromValue(Value value)
static ParseResult parseHWModuleOp(OpAsmParser &parser, OperationState &result)
static LogicalResult verifyAggregateFieldIndexAndType(AggregateOp &op, AggregateType aggType, Type elementType)
Ensure an aggregate op's field index is within the bounds of the aggregate type and the accessed fiel...
static bool hasAdditionalAttributes(Op op, ArrayRef< StringRef > ignoredAttrs={})
Check whether an operation has any additional attributes set beyond its standard list of attributes r...
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
if(parseOptionalKeywordOrOptionalString(parser, result.rawName, found)) return failure()
static InstancePath empty
void setOutput(unsigned i, Value v)
Value getInput(unsigned i)
llvm::SmallVector< Value > outputOperands
llvm::SmallVector< Value > inputArgs
llvm::StringMap< unsigned > outputIdx
llvm::StringMap< unsigned > inputIdx
HWModulePortAccessor(Location loc, const ModulePortInfo &info, Region &bodyRegion)
This helps visit TypeOp nodes.
ResultType dispatchTypeOpVisitor(Operation *op, ExtraArgs... args)
uint64_t getWidth(Type t)
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
std::function< void(std::function< bool(InFlightDiagnostic &)>)> EmitErrorFn
Whenever the nested function returns true, a note referring to the referenced module is attached to t...
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)
BaseTy type_cast(Type type)
bool isCombinational(Operation *op)
Return true if the specified operation is a combinational logic op.
ModulePort::Direction flip(ModulePort::Direction direction)
Flip a port direction.
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function type.
BaseTy type_dyn_cast(Type type)
LogicalResult checkParameterInContext(Attribute value, Operation *module, Operation *usingOp, bool disallowParamRefs=false)
Check parameter specified by value to see if it is valid within the scope of the specified module mod...
llvm::function_ref< void(OpBuilder &, HWModulePortAccessor &)> HWModuleBuilder
bool isValidParameterExpression(Attribute attr, Operation *module)
Return true if the specified attribute tree is made up of nodes that are valid in a parameter express...
LogicalResult aggregateAttrToAPInt(mlir::Type type, ArrayAttr attr, APInt &result)
Convert an ArrayAttr into an APInt value matching the given type.
bool isValidIndexBitWidth(Value index, Value array)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
bool isAnyModuleOrInstance(Operation *module)
TODO: Move all these functions to a hw::ModuleLike interface.
LogicalResult apIntToAggregateAttr(mlir::Type aggregateType, const APInt &intVal, ArrayAttr &result)
Convert an APInt value into a nested aggregate attribute matching the given HWAggregateType.
StringAttr getVerilogModuleNameAttr(Operation *module)
Returns the verilog module name attribute or symbol name of any module-like operations.
mlir::Type getCanonicalType(mlir::Type type)
Recursively remove HW type aliases from a type and its subelements.
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.
StringRef chooseName(StringRef a, StringRef b)
Choose a good name for an item from two options.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
Operation * lookupOp(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds a decoded list of input/inout and output ports for a module or instance.
PortDirectionRange getInputs()
PortDirectionRange getOutputs()