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"
38 case ModulePort::Direction::Input:
39 return ModulePort::Direction::Output;
40 case ModulePort::Direction::Output:
41 return ModulePort::Direction::Input;
42 case ModulePort::Direction::InOut:
43 return ModulePort::Direction::InOut;
45 llvm_unreachable(
"unknown PortDirection");
48bool hw::isValidIndexBitWidth(Value index, Value array) {
49 hw::ArrayType arrayType =
50 dyn_cast<hw::ArrayType>(hw::getCanonicalType(array.getType()));
51 assert(arrayType &&
"expected array type");
52 unsigned indexWidth = index.getType().getIntOrFloatBitWidth();
53 auto requiredWidth = llvm::Log2_64_Ceil(arrayType.getNumElements());
54 return requiredWidth == 0 ? (indexWidth == 0 || indexWidth == 1)
55 : indexWidth == requiredWidth;
59bool hw::isCombinational(Operation *op) {
60 struct IsCombClassifier :
public TypeOpVisitor<IsCombClassifier, bool> {
65 return (op->getDialect() && op->getDialect()->getNamespace() ==
"comb") ||
71 if (
auto structCreate = dyn_cast_or_null<StructCreateOp>(inputOp)) {
72 return structCreate.getOperand(fieldIndex);
76 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
77 if (structInject.getFieldIndex() != fieldIndex)
79 return structInject.getNewValue();
85 ArrayRef<Attribute> attrs) {
87 return ArrayAttr::get(
context, {});
90 if (a && !cast<DictionaryAttr>(a).empty()) {
95 return ArrayAttr::get(
context, {});
96 return ArrayAttr::get(
context, attrs);
102 OpAsmSetValueNameFn setNameFn) {
106 auto module = cast<HWModuleOp>(region.getParentOp());
108 auto *block = ®ion.front();
109 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
110 auto name =
module.getInputName(i);
112 setNameFn(block->getArgument(i), name);
128LogicalResult hw::checkParameterInContext(
129 Attribute value, ArrayAttr moduleParameters,
131 bool disallowParamRefs) {
134 if (isa<IntegerAttr>(value) || isa<FloatAttr>(value) ||
135 isa<StringAttr>(value) || isa<ParamVerbatimAttr>(value))
139 if (
auto expr = dyn_cast<ParamExprAttr>(value)) {
140 for (
auto op : expr.getOperands())
149 if (
auto parameterRef = dyn_cast<ParamDeclRefAttr>(value)) {
150 auto nameAttr = parameterRef.getName();
154 if (disallowParamRefs) {
155 instanceError([&](
auto &diag) {
156 diag <<
"parameter " << nameAttr
157 <<
" cannot be used as a default value for a parameter";
164 for (
auto param : moduleParameters) {
165 auto paramAttr = cast<ParamDeclAttr>(param);
166 if (paramAttr.getName() != nameAttr)
170 if (paramAttr.getType() == parameterRef.getType())
173 instanceError([&](
auto &diag) {
174 diag <<
"parameter " << nameAttr <<
" used with type "
175 << parameterRef.getType() <<
"; should have type "
176 << paramAttr.getType();
182 instanceError([&](
auto &diag) {
183 diag <<
"use of unknown parameter " << nameAttr;
189 instanceError([&](
auto &diag) {
190 diag <<
"invalid parameter value " << value;
202LogicalResult hw::checkParameterInContext(Attribute value, Operation *module,
204 bool disallowParamRefs) {
206 [&](
const std::function<bool(InFlightDiagnostic &)> &fn) {
208 auto diag = usingOp->emitOpError();
210 diag.attachNote(module->getLoc()) <<
"module declared here";
215 module->getAttrOfType<ArrayAttr>(
"parameters"),
216 emitError, disallowParamRefs);
221bool hw::isValidParameterExpression(Attribute attr, Operation *module) {
230 for (
auto [i, barg] : llvm::enumerate(bodyRegion.getArguments())) {
263#include "circt/Dialect/HW/HWCanonicalization.cpp.inc"
270void ConstantOp::print(OpAsmPrinter &p) {
272 p.printAttribute(getValueAttr());
273 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
276ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
277 IntegerAttr valueAttr;
279 if (parser.parseAttribute(valueAttr,
"value", result.attributes) ||
280 parser.parseOptionalAttrDict(result.attributes))
283 result.addTypes(valueAttr.getType());
287LogicalResult ConstantOp::verify() {
291 "hw.constant attribute bitwidth doesn't match return type");
298void ConstantOp::build(OpBuilder &builder, OperationState &result,
299 const APInt &value) {
301 auto type = IntegerType::get(builder.getContext(), value.getBitWidth());
302 auto attr = builder.getIntegerAttr(type, value);
303 return build(builder, result, type, attr);
308void ConstantOp::build(OpBuilder &builder, OperationState &result,
310 return build(builder, result, value.getType(), value);
317void ConstantOp::build(OpBuilder &builder, OperationState &result, Type type,
319 auto numBits = cast<IntegerType>(type).getWidth();
320 build(builder, result,
321 APInt(numBits, (uint64_t)value,
true,
325void ConstantOp::getAsmResultNames(
326 function_ref<
void(Value, StringRef)> setNameFn) {
327 auto intTy = getType();
328 auto intCst = getValue();
331 if (cast<IntegerType>(intTy).
getWidth() == 1)
332 return setNameFn(getResult(), intCst.isZero() ?
"false" :
"true");
335 SmallVector<char, 32> specialNameBuffer;
336 llvm::raw_svector_ostream specialName(specialNameBuffer);
337 specialName <<
'c' << intCst <<
'_' << intTy;
338 setNameFn(getResult(), specialName.str());
341OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
342 assert(adaptor.getOperands().empty() &&
"constant has no operands");
343 return getValueAttr();
354 ArrayRef<StringRef> ignoredAttrs = {}) {
355 auto names = op.getAttributeNames();
356 llvm::SmallDenseSet<StringRef> nameSet;
357 nameSet.reserve(names.size() + ignoredAttrs.size());
358 nameSet.insert(names.begin(), names.end());
359 nameSet.insert(ignoredAttrs.begin(), ignoredAttrs.end());
360 return llvm::any_of(op->getAttrs(), [&](
auto namedAttr) {
361 return !nameSet.contains(namedAttr.getName());
365void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
367 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
368 if (nameAttr && !nameAttr.getValue().empty())
369 setNameFn(getResult(), nameAttr.getValue());
372std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
374OpFoldResult WireOp::fold(FoldAdaptor adaptor) {
383LogicalResult WireOp::canonicalize(WireOp wire, PatternRewriter &rewriter) {
389 if (wire.getInnerSymAttr())
393 if (wire.getInput() == wire.getResult())
398 if (
auto *inputOp = wire.getInput().getDefiningOp())
400 rewriter.modifyOpInPlace(inputOp,
401 [&] { inputOp->setAttr(
"sv.namehint", name); });
403 rewriter.replaceOp(wire, wire.getInput());
413 if (
auto typeAlias = dyn_cast<TypeAliasType>(type))
414 type = typeAlias.getCanonicalType();
416 if (
auto structType = dyn_cast<StructType>(type)) {
417 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
419 return op->emitOpError(
"expected array attribute for constant of type ")
421 if (structType.getElements().size() != arrayAttr.size())
422 return op->emitOpError(
"array attribute (")
423 << arrayAttr.size() <<
") has wrong size for struct constant ("
424 << structType.getElements().size() <<
")";
426 for (
auto [attr, fieldInfo] :
427 llvm::zip(arrayAttr.getValue(), structType.getElements())) {
431 }
else if (
auto arrayType = dyn_cast<ArrayType>(type)) {
432 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
434 return op->emitOpError(
"expected array attribute for constant of type ")
436 if (arrayType.getNumElements() != arrayAttr.size())
437 return op->emitOpError(
"array attribute (")
438 << arrayAttr.size() <<
") has wrong size for array constant ("
439 << arrayType.getNumElements() <<
")";
442 for (
auto attr : arrayAttr.getValue()) {
446 }
else if (
auto arrayType = dyn_cast<UnpackedArrayType>(type)) {
447 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
449 return op->emitOpError(
"expected array attribute for constant of type ")
452 if (arrayType.getNumElements() != arrayAttr.size())
453 return op->emitOpError(
"array attribute (")
455 <<
") has wrong size for unpacked array constant ("
456 << arrayType.getNumElements() <<
")";
458 for (
auto attr : arrayAttr.getValue()) {
462 }
else if (
auto enumType = dyn_cast<EnumType>(type)) {
463 auto stringAttr = dyn_cast<StringAttr>(attr);
465 return op->emitOpError(
"expected string attribute for constant of type ")
467 }
else if (
auto intType = dyn_cast<IntegerType>(type)) {
469 auto intAttr = dyn_cast<IntegerAttr>(attr);
471 return op->emitOpError(
"expected integer attribute for constant of type ")
474 if (intAttr.getValue().getBitWidth() != intType.getWidth())
475 return op->emitOpError(
"hw.constant attribute bitwidth "
476 "doesn't match return type");
477 }
else if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
478 if (typedAttr.getType() != type)
479 return op->emitOpError(
"typed attr doesn't match the return type ")
482 return op->emitOpError(
"unknown element type ") << type;
487LogicalResult AggregateConstantOp::verify() {
491OpFoldResult AggregateConstantOp::fold(FoldAdaptor) {
return getFieldsAttr(); }
499 if (p.parseType(resultType) || p.parseEqual() ||
500 p.parseAttribute(value, resultType))
507 p << resultType <<
" = ";
508 p.printAttributeWithoutType(value);
511LogicalResult ParamValueOp::verify() {
517OpFoldResult ParamValueOp::fold(FoldAdaptor adaptor) {
518 assert(adaptor.getOperands().empty() &&
"hw.param.value has no operands");
519 return getValueAttr();
528 return isa<HWModuleLike, InstanceOp>(moduleOrInstance);
534 return TypeSwitch<Operation *, FunctionType>(moduleOrInstance)
535 .Case<InstanceOp>([](
auto instance) {
536 SmallVector<Type> inputs(instance->getOperandTypes());
537 SmallVector<Type> results(instance->getResultTypes());
538 return FunctionType::get(instance->getContext(), inputs, results);
541 [](
auto mod) {
return mod.getHWModuleType().getFuncType(); })
542 .Default([](Operation *op) {
543 return cast<FunctionType>(
544 cast<mlir::FunctionOpInterface>(op).getFunctionType());
552 auto nameAttr =
module->getAttrOfType<StringAttr>("verilogName");
556 return module->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
559template <
typename ModuleTy>
561buildModule(OpBuilder &builder, OperationState &result, StringAttr name,
563 ArrayRef<NamedAttribute> attributes, StringAttr comment) {
564 using namespace mlir::function_interface_impl;
567 result.addAttribute(SymbolTable::getSymbolAttrName(), name);
569 SmallVector<Attribute> perPortAttrs;
570 SmallVector<ModulePort> portTypes;
572 for (
auto elt : ports) {
573 portTypes.push_back(elt);
574 llvm::SmallVector<NamedAttribute> portAttrs;
576 llvm::copy(elt.attrs, std::back_inserter(portAttrs));
577 perPortAttrs.push_back(builder.getDictionaryAttr(portAttrs));
582 parameters = builder.getArrayAttr({});
585 auto type = ModuleType::get(builder.getContext(), portTypes);
586 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name),
587 TypeAttr::get(type));
588 result.addAttribute(
"per_port_attrs",
590 result.addAttribute(
"parameters", parameters);
592 comment = builder.getStringAttr(
"");
593 result.addAttribute(
"comment", comment);
594 result.addAttributes(attributes);
600 MLIRContext *
context, ArrayRef<std::pair<unsigned, PortInfo>> insertArgs,
601 ArrayRef<unsigned> removeArgs, ArrayRef<Attribute> oldArgNames,
602 ArrayRef<Type> oldArgTypes, ArrayRef<Attribute> oldArgAttrs,
603 ArrayRef<Location> oldArgLocs, SmallVector<Attribute> &newArgNames,
604 SmallVector<Type> &newArgTypes, SmallVector<Attribute> &newArgAttrs,
605 SmallVector<Location> &newArgLocs, Block *body =
nullptr) {
610 assert(llvm::is_sorted(insertArgs,
611 [](
auto &a,
auto &b) {
return a.first < b.first; }) &&
612 "insertArgs must be in ascending order");
613 assert(llvm::is_sorted(removeArgs, [](
auto &a,
auto &b) {
return a < b; }) &&
614 "removeArgs must be in ascending order");
617 auto oldArgCount = oldArgTypes.size();
618 auto newArgCount = oldArgCount + insertArgs.size() - removeArgs.size();
619 assert((
int)newArgCount >= 0);
621 newArgNames.reserve(newArgCount);
622 newArgTypes.reserve(newArgCount);
623 newArgAttrs.reserve(newArgCount);
624 newArgLocs.reserve(newArgCount);
626 auto exportPortAttrName = StringAttr::get(
context,
"hw.exportPort");
627 auto emptyDictAttr = DictionaryAttr::get(
context, {});
628 auto unknownLoc = UnknownLoc::get(
context);
630 BitVector erasedIndices;
632 erasedIndices.resize(oldArgCount + insertArgs.size());
634 for (
unsigned argIdx = 0, idx = 0; argIdx <= oldArgCount; ++argIdx, ++idx) {
636 while (!insertArgs.empty() && insertArgs[0].first == argIdx) {
637 auto port = insertArgs[0].second;
639 !isa<InOutType>(port.type))
640 port.type = InOutType::get(port.type);
641 auto sym = port.getSym();
643 (sym && !sym.empty())
644 ? DictionaryAttr::get(
context, {{exportPortAttrName, sym}})
646 newArgNames.push_back(port.name);
647 newArgTypes.push_back(port.type);
648 newArgAttrs.push_back(attr);
649 insertArgs = insertArgs.drop_front();
650 LocationAttr loc = port.loc ? port.loc : unknownLoc;
651 newArgLocs.push_back(loc);
653 body->insertArgument(idx++, port.type, loc);
655 if (argIdx == oldArgCount)
659 bool removed =
false;
660 while (!removeArgs.empty() && removeArgs[0] == argIdx) {
661 removeArgs = removeArgs.drop_front();
667 erasedIndices.set(idx);
669 newArgNames.push_back(oldArgNames[argIdx]);
670 newArgTypes.push_back(oldArgTypes[argIdx]);
671 newArgAttrs.push_back(oldArgAttrs.empty() ? emptyDictAttr
672 : oldArgAttrs[argIdx]);
673 newArgLocs.push_back(oldArgLocs[argIdx]);
678 body->eraseArguments(erasedIndices);
680 assert(newArgNames.size() == newArgCount);
681 assert(newArgTypes.size() == newArgCount);
682 assert(newArgAttrs.size() == newArgCount);
683 assert(newArgLocs.size() == newArgCount);
697[[deprecated]]
static void
699 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
700 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
701 ArrayRef<unsigned> removeInputs,
702 ArrayRef<unsigned> removeOutputs, Block *body =
nullptr) {
703 auto moduleOp = cast<HWModuleLike>(op);
704 auto *
context = moduleOp.getContext();
707 auto oldArgNames = moduleOp.getInputNames();
708 auto oldArgTypes = moduleOp.getInputTypes();
709 auto oldArgAttrs = moduleOp.getAllInputAttrs();
710 auto oldArgLocs = moduleOp.getInputLocs();
712 auto oldResultNames = moduleOp.getOutputNames();
713 auto oldResultTypes = moduleOp.getOutputTypes();
714 auto oldResultAttrs = moduleOp.getAllOutputAttrs();
715 auto oldResultLocs = moduleOp.getOutputLocs();
718 SmallVector<Attribute> newArgNames, newResultNames;
719 SmallVector<Type> newArgTypes, newResultTypes;
720 SmallVector<Attribute> newArgAttrs, newResultAttrs;
721 SmallVector<Location> newArgLocs, newResultLocs;
724 oldArgTypes, oldArgAttrs, oldArgLocs, newArgNames,
725 newArgTypes, newArgAttrs, newArgLocs, body);
728 oldResultTypes, oldResultAttrs, oldResultLocs,
729 newResultNames, newResultTypes, newResultAttrs,
733 auto fnty = FunctionType::get(
context, newArgTypes, newResultTypes);
735 moduleOp.setHWModuleType(modty);
736 moduleOp.setAllInputAttrs(newArgAttrs);
737 moduleOp.setAllOutputAttrs(newResultAttrs);
739 newArgLocs.append(newResultLocs.begin(), newResultLocs.end());
740 moduleOp.setAllPortLocs(newArgLocs);
743void HWModuleOp::build(OpBuilder &builder, OperationState &result,
745 ArrayAttr parameters,
746 ArrayRef<NamedAttribute> attributes, StringAttr comment,
747 bool shouldEnsureTerminator) {
748 buildModule<HWModuleOp>(builder, result, name, ports, parameters, attributes,
752 auto *bodyRegion = result.regions[0].get();
754 bodyRegion->push_back(body);
757 auto unknownLoc = builder.getUnknownLoc();
758 for (
auto port : ports.getInputs()) {
759 auto loc = port.loc ? Location(port.loc) : unknownLoc;
760 auto type = port.type;
761 if (port.isInOut() && !isa<InOutType>(type))
762 type = InOutType::get(type);
763 body->addArgument(type, loc);
767 auto unknownLocAttr = cast<LocationAttr>(unknownLoc);
768 SmallVector<Attribute> resultLocs;
769 for (
auto port : ports.getOutputs())
770 resultLocs.push_back(port.loc ? port.loc : unknownLocAttr);
771 result.addAttribute(
"result_locs", builder.getArrayAttr(resultLocs));
773 if (shouldEnsureTerminator)
774 HWModuleOp::ensureTerminator(*bodyRegion, builder, result.location);
777void HWModuleOp::build(OpBuilder &builder, OperationState &result,
778 StringAttr name, ArrayRef<PortInfo> ports,
779 ArrayAttr parameters,
780 ArrayRef<NamedAttribute> attributes,
781 StringAttr comment) {
782 build(builder, result, name,
ModulePortInfo(ports), parameters, attributes,
786void HWModuleOp::build(OpBuilder &builder, OperationState &odsState,
789 ArrayRef<NamedAttribute> attributes,
790 StringAttr comment) {
791 build(builder, odsState, name, ports, parameters, attributes, comment,
793 auto *bodyRegion = odsState.regions[0].get();
794 OpBuilder::InsertionGuard guard(builder);
796 builder.setInsertionPointToEnd(&bodyRegion->front());
797 modBuilder(builder, accessor);
799 llvm::SmallVector<Value> outputOperands = accessor.getOutputOperands();
800 hw::OutputOp::create(builder, odsState.location, outputOperands);
803void HWModuleOp::modifyPorts(
804 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
805 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
806 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
814StringAttr HWModuleExternOp::getVerilogModuleNameAttr() {
815 if (
auto vName = getVerilogNameAttr())
818 return (*this)->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
821StringAttr HWModuleGeneratedOp::getVerilogModuleNameAttr() {
822 if (
auto vName = getVerilogNameAttr()) {
825 return (*this)->getAttrOfType<StringAttr>(
826 ::mlir::SymbolTable::getSymbolAttrName());
829void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
831 StringRef verilogName, ArrayAttr parameters,
832 ArrayRef<NamedAttribute> attributes) {
833 buildModule<HWModuleExternOp>(builder, result, name, ports, parameters,
837 LocationAttr unknownLoc = builder.getUnknownLoc();
838 SmallVector<Attribute> portLocs;
839 for (
auto elt : ports)
840 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
841 result.addAttribute(
"port_locs", builder.getArrayAttr(portLocs));
843 if (!verilogName.empty())
844 result.addAttribute(
"verilogName", builder.getStringAttr(verilogName));
847void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
848 StringAttr name, ArrayRef<PortInfo> ports,
849 StringRef verilogName, ArrayAttr parameters,
850 ArrayRef<NamedAttribute> attributes) {
851 build(builder, result, name,
ModulePortInfo(ports), verilogName, parameters,
855void HWModuleExternOp::modifyPorts(
856 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
857 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
858 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
863void HWModuleExternOp::appendOutputs(
864 ArrayRef<std::pair<StringAttr, Value>> outputs) {}
866void HWModuleGeneratedOp::build(OpBuilder &builder, OperationState &result,
867 FlatSymbolRefAttr genKind, StringAttr name,
869 StringRef verilogName, ArrayAttr parameters,
870 ArrayRef<NamedAttribute> attributes) {
871 buildModule<HWModuleGeneratedOp>(builder, result, name, ports, parameters,
874 LocationAttr unknownLoc = builder.getUnknownLoc();
875 SmallVector<Attribute> portLocs;
876 for (
auto elt : ports)
877 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
878 result.addAttribute(
"port_locs", builder.getArrayAttr(portLocs));
880 result.addAttribute(
"generatorKind", genKind);
881 if (!verilogName.empty())
882 result.addAttribute(
"verilogName", builder.getStringAttr(verilogName));
885void HWModuleGeneratedOp::build(OpBuilder &builder, OperationState &result,
886 FlatSymbolRefAttr genKind, StringAttr name,
887 ArrayRef<PortInfo> ports, StringRef verilogName,
888 ArrayAttr parameters,
889 ArrayRef<NamedAttribute> attributes) {
890 build(builder, result, genKind, name,
ModulePortInfo(ports), verilogName,
891 parameters, attributes);
894void HWModuleGeneratedOp::modifyPorts(
895 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
896 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
897 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
902void HWModuleGeneratedOp::appendOutputs(
903 ArrayRef<std::pair<StringAttr, Value>> outputs) {}
905static bool hasAttribute(StringRef name, ArrayRef<NamedAttribute> attrs) {
906 for (
auto &argAttr : attrs)
907 if (argAttr.getName() == name)
912template <
typename ModuleTy>
914 OperationState &result) {
916 using namespace mlir::function_interface_impl;
917 auto builder = parser.getBuilder();
918 auto loc = parser.getCurrentLocation();
921 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
925 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
930 FlatSymbolRefAttr kindAttr;
931 if constexpr (std::is_same_v<ModuleTy, HWModuleGeneratedOp>) {
932 if (parser.parseComma() ||
933 parser.parseAttribute(kindAttr,
"generatorKind", result.attributes)) {
939 ArrayAttr parameters;
943 SmallVector<module_like_impl::PortParse> ports;
949 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
953 parser.emitError(loc,
"explicit `parameters` attributes not allowed");
957 result.addAttribute(
"parameters", parameters);
958 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name), modType);
962 SmallVector<Attribute> attrs;
963 for (
auto &port : ports)
964 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
966 auto nonEmptyAttrsFn = [](Attribute attr) {
967 return attr && !cast<DictionaryAttr>(attr).empty();
969 if (llvm::any_of(attrs, nonEmptyAttrsFn))
970 result.addAttribute(ModuleTy::getPerPortAttrsAttrName(result.name),
971 builder.getArrayAttr(attrs));
974 auto unknownLoc = builder.getUnknownLoc();
975 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
976 return attr && cast<Location>(attr) != unknownLoc;
978 SmallVector<Attribute> locs;
979 StringAttr portLocsAttrName;
980 if constexpr (std::is_same_v<ModuleTy, HWModuleOp>) {
983 portLocsAttrName = ModuleTy::getResultLocsAttrName(result.name);
984 for (
auto &port : ports)
986 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
989 portLocsAttrName = ModuleTy::getPortLocsAttrName(result.name);
990 for (
auto &port : ports)
991 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
993 if (llvm::any_of(locs, nonEmptyLocsFn))
994 result.addAttribute(portLocsAttrName, builder.getArrayAttr(locs));
997 SmallVector<OpAsmParser::Argument, 4> entryArgs;
998 for (
auto &port : ports)
1000 entryArgs.push_back(port);
1003 auto *body = result.addRegion();
1004 if (std::is_same_v<ModuleTy, HWModuleOp>) {
1005 if (parser.parseRegion(*body, entryArgs))
1008 HWModuleOp::ensureTerminator(*body, parser.getBuilder(), result.location);
1013ParseResult HWModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1014 return parseHWModuleOp<HWModuleOp>(parser, result);
1017ParseResult HWModuleExternOp::parse(OpAsmParser &parser,
1018 OperationState &result) {
1019 return parseHWModuleOp<HWModuleExternOp>(parser, result);
1022ParseResult HWModuleGeneratedOp::parse(OpAsmParser &parser,
1023 OperationState &result) {
1024 return parseHWModuleOp<HWModuleGeneratedOp>(parser, result);
1028 if (
auto mod = dyn_cast<HWModuleLike>(op))
1029 return mod.getHWModuleType().getFuncType();
1030 return cast<FunctionType>(
1031 cast<mlir::FunctionOpInterface>(op).getFunctionType());
1034template <
typename ModuleTy>
1038 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1039 if (
auto visibility = mod.getOperation()->template getAttrOfType<StringAttr>(
1040 visibilityAttrName))
1041 p << visibility.getValue() <<
' ';
1044 p.printSymbolName(SymbolTable::getSymbolName(mod.getOperation()).getValue());
1045 if (
auto gen = dyn_cast<HWModuleGeneratedOp>(mod.getOperation())) {
1047 p.printSymbolName(gen.getGeneratorKind());
1055 SmallVector<StringRef, 3> omittedAttrs;
1056 if (isa<HWModuleGeneratedOp>(mod.getOperation()))
1057 omittedAttrs.push_back(
"generatorKind");
1058 if constexpr (std::is_same_v<ModuleTy, HWModuleOp>)
1059 omittedAttrs.push_back(mod.getResultLocsAttrName());
1061 omittedAttrs.push_back(mod.getPortLocsAttrName());
1062 omittedAttrs.push_back(mod.getModuleTypeAttrName());
1063 omittedAttrs.push_back(mod.getPerPortAttrsAttrName());
1064 omittedAttrs.push_back(mod.getParametersAttrName());
1065 omittedAttrs.push_back(visibilityAttrName);
1067 mod.getOperation()->template getAttrOfType<StringAttr>(
"comment"))
1068 if (cmt.getValue().empty())
1069 omittedAttrs.push_back(
"comment");
1071 mlir::function_interface_impl::printFunctionAttributes(p, mod.getOperation(),
1075void HWModuleExternOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1076void HWModuleGeneratedOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1078void HWModuleOp::print(OpAsmPrinter &p) {
1082 Region &body = getBody();
1083 if (!body.empty()) {
1085 p.printRegion(body,
false,
1091 assert(isa<HWModuleLike>(module) &&
1092 "verifier hook should only be called on modules");
1094 if (
auto portLocs = module->getAttrOfType<ArrayAttr>(
"port_locs"))
1095 if (!portLocs.empty() && portLocs.size() != module.getNumPorts())
1096 return module->emitOpError("requires ")
1097 << module.getNumPorts() << " port locations but got "
1100 SmallPtrSet<Attribute, 4> paramNames;
1103 for (
auto param :
module->getAttrOfType<ArrayAttr>("parameters")) {
1104 auto paramAttr = cast<ParamDeclAttr>(param);
1108 if (!paramNames.insert(paramAttr.getName()).second)
1109 return module->emitOpError("parameter ")
1110 << paramAttr << " has the same name as a previous parameter";
1113 auto value = paramAttr.getValue();
1117 auto typedValue = dyn_cast<TypedAttr>(value);
1119 return module->emitOpError("parameter ")
1120 << paramAttr << " should have a typed value; has value
" << value;
1122 if (typedValue.getType() != paramAttr.getType())
1123 return module->emitOpError("parameter
")
1124 << paramAttr << " should have type
" << paramAttr.getType()
1125 << "; has type
" << typedValue.getType();
1127 // Verify that this is a valid parameter value, disallowing parameter
1128 // references. We could allow parameters to refer to each other in the
1129 // future with lexical ordering if there is a need.
1130 if (failed(checkParameterInContext(value, module, module,
1131 /*disallowParamRefs=*/true)))
1137LogicalResult HWModuleOp::verify() {
1138 if (failed(verifyModuleCommon(*this)))
1141 auto type = getModuleType();
1142 auto *body = getBodyBlock();
1144 // Verify the number of block arguments.
1145 auto numInputs = type.getNumInputs();
1146 if (body->getNumArguments() != numInputs)
1147 return emitOpError("entry block must have
")
1148 << numInputs << " arguments to match
module signature";
1155std::pair<StringAttr, BlockArgument>
1156HWModuleOp::insertInput(
unsigned index, StringAttr name, Type ty) {
1160 for (
auto port : ports)
1161 ns.newName(port.name.getValue());
1162 auto nameAttr = StringAttr::get(getContext(), ns.
newName(name.getValue()));
1168 port.
name = nameAttr;
1175 return {nameAttr, body->getArgument(index)};
1178void HWModuleOp::insertOutputs(
unsigned index,
1179 ArrayRef<std::pair<StringAttr, Value>> outputs) {
1181 auto output = cast<OutputOp>(
getBodyBlock()->getTerminator());
1182 assert(index <= output->getNumOperands() &&
"invalid output index");
1185 SmallVector<std::pair<unsigned, PortInfo>> indexedNewPorts;
1186 for (
auto &[name, value] : outputs) {
1190 port.
type = value.getType();
1191 indexedNewPorts.emplace_back(index, port);
1197 for (
auto &[name, value] : outputs)
1198 output->insertOperands(index++, value);
1201void HWModuleOp::appendOutputs(ArrayRef<std::pair<StringAttr, Value>> outputs) {
1202 return insertOutputs(getNumOutputPorts(), outputs);
1205void HWModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1210void HWModuleExternOp::getAsmBlockArgumentNames(
1215template <
typename ModTy>
1217 auto locs =
module.getPortLocs();
1219 SmallVector<Location> retval;
1220 retval.reserve(locs->size());
1221 for (
auto l : *locs)
1222 retval.push_back(cast<Location>(l));
1224 assert(!locs->size() || locs->size() == module.getNumPorts());
1227 return SmallVector<Location>(module.getNumPorts(),
1228 UnknownLoc::get(module.getContext()));
1231SmallVector<Location> HWModuleOp::getAllPortLocs() {
1232 SmallVector<Location> portLocs;
1234 auto resultLocs = getResultLocsAttr();
1235 unsigned inputCount = 0;
1237 auto unknownLoc = UnknownLoc::get(getContext());
1239 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
1240 if (modType.isOutput(i)) {
1241 auto loc = resultLocs
1243 resultLocs.getValue()[portLocs.size() - inputCount])
1245 portLocs.push_back(loc);
1247 auto loc = body ? body->getArgument(inputCount).getLoc() : unknownLoc;
1248 portLocs.push_back(loc);
1255SmallVector<Location> HWModuleExternOp::getAllPortLocs() {
1256 return ::getAllPortLocs(*
this);
1259SmallVector<Location> HWModuleGeneratedOp::getAllPortLocs() {
1260 return ::getAllPortLocs(*
this);
1263void HWModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1264 SmallVector<Attribute> resultLocs;
1265 unsigned inputCount = 0;
1268 for (
unsigned i = 0, e =
getNumPorts(); i < e; ++i) {
1269 if (modType.isOutput(i))
1270 resultLocs.push_back(locs[i]);
1272 body->getArgument(inputCount++).setLoc(cast<Location>(locs[i]));
1274 setResultLocsAttr(ArrayAttr::get(getContext(), resultLocs));
1277void HWModuleExternOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1278 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
1281void HWModuleGeneratedOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
1282 setPortLocsAttr(ArrayAttr::get(getContext(), locs));
1285template <
typename ModTy>
1287 auto numInputs =
module.getNumInputPorts();
1288 SmallVector<Attribute> argNames(names.begin(), names.begin() + numInputs);
1289 SmallVector<Attribute> resNames(names.begin() + numInputs, names.end());
1290 auto oldType =
module.getModuleType();
1291 SmallVector<ModulePort> newPorts(oldType.getPorts().begin(),
1292 oldType.getPorts().end());
1293 for (
size_t i = 0UL, e = newPorts.size(); i != e; ++i)
1294 newPorts[i].name = cast<StringAttr>(names[i]);
1295 auto newType = ModuleType::get(module.getContext(), newPorts);
1296 module.setModuleType(newType);
1299void HWModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
1303void HWModuleExternOp::setAllPortNames(ArrayRef<Attribute> names) {
1307void HWModuleGeneratedOp::setAllPortNames(ArrayRef<Attribute> names) {
1311ArrayRef<Attribute> HWModuleOp::getAllPortAttrs() {
1312 auto attrs = getPerPortAttrs();
1313 if (attrs && !attrs->empty())
1314 return attrs->getValue();
1318ArrayRef<Attribute> HWModuleExternOp::getAllPortAttrs() {
1319 auto attrs = getPerPortAttrs();
1320 if (attrs && !attrs->empty())
1321 return attrs->getValue();
1325ArrayRef<Attribute> HWModuleGeneratedOp::getAllPortAttrs() {
1326 auto attrs = getPerPortAttrs();
1327 if (attrs && !attrs->empty())
1328 return attrs->getValue();
1332void HWModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1333 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1336void HWModuleExternOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1337 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1340void HWModuleGeneratedOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1341 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1344void HWModuleOp::removeAllPortAttrs() {
1345 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1348void HWModuleExternOp::removeAllPortAttrs() {
1349 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1352void HWModuleGeneratedOp::removeAllPortAttrs() {
1353 setPerPortAttrsAttr(ArrayAttr::get(getContext(), {}));
1358template <
typename ModTy>
1360 auto argAttrs = mod.getAllInputAttrs();
1361 auto resAttrs = mod.getAllOutputAttrs();
1362 mod.setModuleTypeAttr(TypeAttr::get(type));
1363 unsigned newNumArgs = type.getNumInputs();
1364 unsigned newNumResults = type.getNumOutputs();
1366 auto emptyDict = DictionaryAttr::get(mod.getContext());
1367 argAttrs.resize(newNumArgs, emptyDict);
1368 resAttrs.resize(newNumResults, emptyDict);
1370 SmallVector<Attribute> attrs;
1371 attrs.append(argAttrs.begin(), argAttrs.end());
1372 attrs.append(resAttrs.begin(), resAttrs.end());
1375 return mod.removeAllPortAttrs();
1376 mod.setAllPortAttrs(attrs);
1379void HWModuleOp::setHWModuleType(ModuleType type) {
1380 return ::setHWModuleType(*
this, type);
1383void HWModuleExternOp::setHWModuleType(ModuleType type) {
1384 return ::setHWModuleType(*
this, type);
1387void HWModuleGeneratedOp::setHWModuleType(ModuleType type) {
1388 return ::setHWModuleType(*
this, type);
1393Operation *HWModuleGeneratedOp::getGeneratorKindOp() {
1394 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1395 return topLevelModuleOp.lookupSymbol(getGeneratorKind());
1399HWModuleGeneratedOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1400 auto *referencedKind =
1401 symbolTable.lookupNearestSymbolFrom(*
this, getGeneratorKindAttr());
1403 if (referencedKind ==
nullptr)
1404 return emitError(
"Cannot find generator definition '")
1405 << getGeneratorKind() <<
"'";
1407 if (!isa<HWGeneratorSchemaOp>(referencedKind))
1408 return emitError(
"Symbol resolved to '")
1409 << referencedKind->getName()
1410 <<
"' which is not a HWGeneratorSchemaOp";
1412 auto referencedKindOp = dyn_cast<HWGeneratorSchemaOp>(referencedKind);
1413 auto paramRef = referencedKindOp.getRequiredAttrs();
1414 auto dict = (*this)->getAttrDictionary();
1415 for (
auto str : paramRef) {
1416 auto strAttr = dyn_cast<StringAttr>(str);
1418 return emitError(
"Unknown attribute type, expected a string");
1419 if (!dict.get(strAttr.getValue()))
1420 return emitError(
"Missing attribute '") << strAttr.getValue() <<
"'";
1426LogicalResult HWModuleGeneratedOp::verify() {
1430void HWModuleGeneratedOp::getAsmBlockArgumentNames(
1435LogicalResult HWModuleOp::verifyBody() {
return success(); }
1437template <
typename ModuleTy>
1439 auto modTy = mod.getHWModuleType();
1440 auto emptyDict = DictionaryAttr::get(mod.getContext());
1441 SmallVector<PortInfo> retval;
1442 auto locs = mod.getAllPortLocs();
1443 for (
unsigned i = 0, e = modTy.getNumPorts(); i < e; ++i) {
1444 LocationAttr loc = locs[i];
1445 DictionaryAttr attrs =
1446 dyn_cast_or_null<DictionaryAttr>(mod.getPortAttrs(i));
1449 retval.push_back({modTy.getPorts()[i],
1450 modTy.isOutput(i) ? modTy.getOutputIdForPortId(i)
1451 : modTy.getInputIdForPortId(i),
1457template <
typename ModuleTy>
1459 auto modTy = mod.getHWModuleType();
1460 auto emptyDict = DictionaryAttr::get(mod.getContext());
1461 LocationAttr loc = mod.getPortLoc(idx);
1462 DictionaryAttr attrs =
1463 dyn_cast_or_null<DictionaryAttr>(mod.getPortAttrs(idx));
1466 return {modTy.getPorts()[idx],
1467 modTy.isOutput(idx) ? modTy.getOutputIdForPortId(idx)
1468 : modTy.getInputIdForPortId(idx),
1477void InstanceOp::build(OpBuilder &builder, OperationState &result,
1478 Operation *module, StringAttr name,
1479 ArrayRef<Value> inputs, ArrayAttr parameters,
1480 InnerSymAttr innerSym) {
1482 parameters = builder.getArrayAttr({});
1484 auto mod = cast<hw::HWModuleLike>(module);
1485 auto argNames = builder.getArrayAttr(mod.getInputNames());
1486 auto resultNames = builder.getArrayAttr(mod.getOutputNames());
1491 ModuleType modType = mod.getHWModuleType();
1492 FailureOr<ModuleType> resolvedModType = modType.resolveParametricTypes(
1493 parameters, result.location,
false);
1494 if (succeeded(resolvedModType))
1495 modType = *resolvedModType;
1496 FunctionType funcType = resolvedModType->getFuncType();
1497 build(builder, result, funcType.getResults(), name,
1498 FlatSymbolRefAttr::get(SymbolTable::getSymbolName(module)), inputs,
1499 argNames, resultNames, parameters, innerSym, {});
1502std::optional<size_t> InstanceOp::getTargetResultIndex() {
1504 return std::nullopt;
1507LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1509 *
this, getModuleNameAttr(), getInputs(), getResultTypes(), getArgNames(),
1510 getResultNames(), getParameters(), symbolTable);
1513LogicalResult InstanceOp::verify() {
1514 auto module = (*this)->getParentOfType<HWModuleOp>();
1518 auto moduleParameters =
module->getAttrOfType<ArrayAttr>("parameters");
1520 [&](
const std::function<bool(InFlightDiagnostic &)> &fn) {
1521 auto diag = emitOpError();
1523 diag.attachNote(module->getLoc()) <<
"module declared here";
1526 getParameters(), moduleParameters, emitError);
1529ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
1530 StringAttr instanceNameAttr;
1531 InnerSymAttr innerSym;
1532 FlatSymbolRefAttr moduleNameAttr;
1533 SmallVector<OpAsmParser::UnresolvedOperand, 4> inputsOperands;
1534 SmallVector<Type, 1> inputsTypes, allResultTypes;
1535 ArrayAttr argNames, resultNames, parameters;
1536 auto noneType = parser.getBuilder().getType<NoneType>();
1538 if (parser.parseAttribute(instanceNameAttr, noneType,
"instanceName",
1542 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1545 if (parser.parseCustomAttributeWithFallback(innerSym))
1550 llvm::SMLoc parametersLoc, inputsOperandsLoc;
1551 if (parser.parseAttribute(moduleNameAttr, noneType,
"moduleName",
1552 result.attributes) ||
1553 parser.getCurrentLocation(¶metersLoc) ||
1556 parser.resolveOperands(inputsOperands, inputsTypes, inputsOperandsLoc,
1558 parser.parseArrow() ||
1560 parser.parseOptionalAttrDict(result.attributes)) {
1564 result.addAttribute(
"argNames", argNames);
1565 result.addAttribute(
"resultNames", resultNames);
1566 result.addAttribute(
"parameters", parameters);
1567 result.addTypes(allResultTypes);
1571void InstanceOp::print(OpAsmPrinter &p) {
1573 p.printAttributeWithoutType(getInstanceNameAttr());
1574 if (
auto attr = getInnerSymAttr()) {
1579 p.printAttributeWithoutType(getModuleNameAttr());
1586 p.printOptionalAttrDict(
1587 (*this)->getAttrs(),
1589 InnerSymbolTable::getInnerSymbolAttrName(),
"moduleName",
1590 "argNames",
"resultNames",
"parameters"});
1598LogicalResult OutputOp::verify() {
1602 if (
auto mod = dyn_cast<HWModuleOp>((*this)->getParentOp()))
1603 modType = mod.getHWModuleType();
1605 emitOpError(
"must have a module parent");
1608 auto modResults = modType.getOutputTypes();
1609 OperandRange outputValues = getOperands();
1610 if (modResults.size() != outputValues.size()) {
1611 emitOpError(
"must have same number of operands as region results.");
1616 for (
size_t i = 0, e = modResults.size(); i < e; ++i) {
1617 if (modResults[i] != outputValues[i].getType()) {
1618 emitOpError(
"output types must match module. In "
1620 << i <<
", expected " << modResults[i] <<
", but got "
1621 << outputValues[i].getType() <<
".";
1636 if (p.parseType(type))
1637 return p.emitError(p.getCurrentLocation(),
"Expected type");
1638 auto arrType = type_dyn_cast<ArrayType>(type);
1640 return p.emitError(p.getCurrentLocation(),
"Expected !hw.array type");
1642 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1643 idxType = IntegerType::get(p.getBuilder().getContext(), idxWidth);
1649 p.printType(srcType);
1652ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
1653 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
1654 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
1657 if (parser.parseOperandList(operands) ||
1658 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
1659 parser.parseType(elemType))
1662 if (operands.size() == 0)
1663 return parser.emitError(inputOperandsLoc,
1664 "Cannot construct an array of length 0");
1668 if (parser.parseOptionalArrow().succeeded()) {
1669 if (parser.parseType(resultType))
1671 result.addTypes(resultType);
1673 result.addTypes({ArrayType::get(elemType, operands.size())});
1676 for (
auto operand : operands)
1677 if (parser.resolveOperand(operand, elemType, result.operands))
1682void ArrayCreateOp::print(OpAsmPrinter &p) {
1684 p.printOperands(getInputs());
1685 p.printOptionalAttrDict((*this)->getAttrs());
1686 p <<
" : " << getInputs()[0].getType();
1690 ArrayType::get(getInputs()[0].getType(), getInputs().size());
1691 if (getType() != expectedType)
1692 p <<
" -> " << getType();
1695void ArrayCreateOp::build(OpBuilder &b, OperationState &state,
1696 ValueRange values) {
1697 assert(values.size() > 0 &&
"Cannot build array of zero elements");
1698 Type elemType = values[0].getType();
1701 [elemType](Value v) ->
bool {
return v.getType() == elemType; }) &&
1702 "All values must have same type.");
1703 build(b, state, ArrayType::get(elemType, values.size()), values);
1706LogicalResult ArrayCreateOp::verify() {
1707 unsigned returnSize = hw::type_cast<ArrayType>(getType()).getNumElements();
1708 if (getInputs().size() != returnSize)
1713OpFoldResult ArrayCreateOp::fold(FoldAdaptor adaptor) {
1714 if (llvm::any_of(adaptor.getInputs(), [](Attribute attr) {
1715 return !isa_and_nonnull<IntegerAttr>(attr);
1718 return ArrayAttr::get(getContext(), adaptor.getInputs());
1728 auto baseValue = constBase.getValue();
1729 auto indexValue = constIndex.getValue();
1731 unsigned bits = baseValue.getBitWidth();
1732 assert(bits == indexValue.getBitWidth() &&
"mismatched widths");
1734 if (bits < 64 && offset >= (1ull << bits))
1737 APInt baseExt = baseValue.zextOrTrunc(bits + 1);
1738 APInt indexExt = indexValue.zextOrTrunc(bits + 1);
1739 return baseExt + offset == indexExt;
1747 PatternRewriter &rewriter) {
1749 auto arrayTy = hw::type_cast<ArrayType>(op.getType());
1750 if (arrayTy.getNumElements() <= 1)
1752 auto elemTy = arrayTy.getElementType();
1761 SmallVector<Chunk> chunks;
1762 for (Value value : llvm::reverse(op.getInputs())) {
1763 auto get = value.getDefiningOp<
ArrayGetOp>();
1767 Value input = get.getInput();
1768 Value index = get.getIndex();
1769 if (!chunks.empty()) {
1770 auto &c = *chunks.rbegin();
1771 if (c.input == get.getInput() &&
isOffset(c.index, index, c.size)) {
1777 chunks.push_back(Chunk{input, index, 1});
1781 if (chunks.size() == 1) {
1782 auto &chunk = chunks[0];
1783 rewriter.replaceOp(op, rewriter.createOrFold<
ArraySliceOp>(
1784 op.getLoc(), arrayTy, chunk.input, chunk.index));
1790 if (chunks.size() * 2 < arrayTy.getNumElements()) {
1791 SmallVector<Value> slices;
1792 for (
auto &chunk : llvm::reverse(chunks)) {
1793 auto sliceTy = ArrayType::get(elemTy, chunk.size);
1795 op.getLoc(), sliceTy, chunk.input, chunk.index));
1797 rewriter.replaceOpWithNewOp<
ArrayConcatOp>(op, arrayTy, slices);
1805 PatternRewriter &rewriter) {
1811Value ArrayCreateOp::getUniformElement() {
1812 if (!getInputs().
empty() && llvm::all_equal(getInputs()))
1813 return getInputs()[0];
1818 auto idxOp = dyn_cast_or_null<ConstantOp>(value.getDefiningOp());
1820 return std::nullopt;
1821 APInt idxAttr = idxOp.getValue();
1822 if (idxAttr.getBitWidth() > 64)
1823 return std::nullopt;
1824 return idxAttr.getLimitedValue();
1827LogicalResult ArraySliceOp::verify() {
1828 unsigned inputSize =
1829 type_cast<ArrayType>(getInput().getType()).getNumElements();
1830 if (llvm::Log2_64_Ceil(inputSize) !=
1831 getLowIndex().getType().getIntOrFloatBitWidth())
1833 "ArraySlice: index width must match clog2 of array size");
1837OpFoldResult ArraySliceOp::fold(FoldAdaptor adaptor) {
1839 if (getType() == getInput().getType())
1844LogicalResult ArraySliceOp::canonicalize(
ArraySliceOp op,
1845 PatternRewriter &rewriter) {
1846 auto sliceTy = hw::type_cast<ArrayType>(op.getType());
1847 auto elemTy = sliceTy.getElementType();
1848 uint64_t sliceSize = sliceTy.getNumElements();
1852 if (sliceSize == 1) {
1856 rewriter.replaceOpWithNewOp<
ArrayCreateOp>(op, op.getType(),
1865 auto *inputOp = op.getInput().getDefiningOp();
1866 if (
auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
1868 if (inputSlice == op)
1871 auto inputIndex = inputSlice.getLowIndex();
1873 if (!inputOffsetOpt)
1876 uint64_t offset = *offsetOpt + *inputOffsetOpt;
1879 rewriter.replaceOpWithNewOp<
ArraySliceOp>(op, op.getType(),
1880 inputSlice.getInput(), lowIndex);
1884 if (
auto inputCreate = dyn_cast_or_null<ArrayCreateOp>(inputOp)) {
1886 auto inputs = inputCreate.getInputs();
1888 uint64_t begin = inputs.size() - *offsetOpt - sliceSize;
1889 rewriter.replaceOpWithNewOp<
ArrayCreateOp>(op, op.getType(),
1890 inputs.slice(begin, sliceSize));
1894 if (
auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
1896 SmallVector<Value> chunks;
1897 uint64_t sliceStart = *offsetOpt;
1898 for (
auto input :
llvm::reverse(inputConcat.getInputs())) {
1900 uint64_t inputSize =
1901 hw::type_cast<ArrayType>(input.getType()).getNumElements();
1902 if (inputSize == 0 || inputSize <= sliceStart) {
1903 sliceStart -= inputSize;
1908 uint64_t cutEnd = std::min(inputSize, sliceStart + sliceSize);
1909 uint64_t cutSize = cutEnd - sliceStart;
1910 assert(cutSize != 0 &&
"slice cannot be empty");
1912 if (cutSize == inputSize) {
1914 assert(sliceStart == 0 &&
"invalid cut size");
1915 chunks.push_back(input);
1918 unsigned width = inputSize == 1 ? 1 : llvm::Log2_64_Ceil(inputSize);
1920 rewriter, op.getLoc(), rewriter.getIntegerType(width), sliceStart);
1922 rewriter, op.getLoc(), hw::ArrayType::get(elemTy, cutSize), input,
1927 sliceSize -= cutSize;
1932 assert(chunks.size() > 0 &&
"missing sliced items");
1933 if (chunks.size() == 1)
1934 rewriter.replaceOp(op, chunks[0]);
1937 op, llvm::to_vector(llvm::reverse(chunks)));
1948 SmallVectorImpl<Type> &inputTypes,
1951 uint64_t resultSize = 0;
1953 auto parseElement = [&]() -> ParseResult {
1955 if (p.parseType(ty))
1957 auto arrTy = type_dyn_cast<ArrayType>(ty);
1959 return p.emitError(p.getCurrentLocation(),
"Expected !hw.array type");
1960 if (elemType && elemType != arrTy.getElementType())
1961 return p.emitError(p.getCurrentLocation(),
"Expected array element type ")
1964 elemType = arrTy.getElementType();
1965 inputTypes.push_back(ty);
1966 resultSize += arrTy.getNumElements();
1970 if (p.parseCommaSeparatedList(parseElement))
1973 resultType = ArrayType::get(elemType, resultSize);
1978 TypeRange inputTypes, Type resultType) {
1979 llvm::interleaveComma(inputTypes, p, [&p](Type t) { p << t; });
1982void ArrayConcatOp::build(OpBuilder &b, OperationState &state,
1983 ValueRange values) {
1984 assert(!values.empty() &&
"Cannot build array of zero elements");
1985 ArrayType arrayTy = cast<ArrayType>(values[0].getType());
1986 Type elemTy = arrayTy.getElementType();
1987 assert(llvm::all_of(values,
1988 [elemTy](Value v) ->
bool {
1989 return isa<ArrayType>(v.getType()) &&
1990 cast<ArrayType>(v.getType()).getElementType() ==
1993 "All values must be of ArrayType with the same element type.");
1995 uint64_t resultSize = 0;
1996 for (Value val : values)
1997 resultSize += cast<ArrayType>(val.getType()).getNumElements();
1998 build(b, state, ArrayType::get(elemTy, resultSize), values);
2001OpFoldResult ArrayConcatOp::fold(FoldAdaptor adaptor) {
2002 if (getInputs().size() == 1)
2003 return getInputs()[0];
2005 auto inputs = adaptor.getInputs();
2006 SmallVector<Attribute> array;
2007 for (
size_t i = 0, e = getNumOperands(); i < e; ++i) {
2010 llvm::copy(cast<ArrayAttr>(inputs[i]), std::back_inserter(array));
2012 return ArrayAttr::get(getContext(), array);
2017 for (
auto input : op.getInputs())
2021 SmallVector<Value> items;
2022 for (
auto input : op.getInputs()) {
2023 auto create = cast<ArrayCreateOp>(input.getDefiningOp());
2024 for (
auto item : create.getInputs())
2025 items.push_back(item);
2039 SmallVector<Location> locs;
2042 SmallVector<Value> items;
2043 std::optional<Slice> last;
2044 bool changed =
false;
2046 auto concatenate = [&] {
2051 items.push_back(last->op);
2059 auto loc = FusedLoc::get(op.getContext(), last->locs);
2060 auto origTy = hw::type_cast<ArrayType>(last->input.getType());
2061 auto arrayTy = ArrayType::get(origTy.getElementType(), last->size);
2063 loc, arrayTy, last->input, last->index));
2068 auto append = [&](Value op, Value input, Value index,
size_t size) {
2073 if (last->input == input &&
isOffset(last->index, index, last->size)) {
2076 last->locs.push_back(op.getLoc());
2081 last.emplace(Slice{input, index, size, op, {op.getLoc()}});
2084 for (
auto item : llvm::reverse(op.getInputs())) {
2086 auto size = hw::type_cast<ArrayType>(slice.getType()).getNumElements();
2087 append(item, slice.getInput(), slice.getLowIndex(), size);
2092 if (create.getInputs().size() == 1) {
2093 if (
auto get = create.getInputs()[0].getDefiningOp<
ArrayGetOp>()) {
2094 append(item, get.getInput(), get.getIndex(), 1);
2101 items.push_back(item);
2108 if (items.size() == 1) {
2109 rewriter.replaceOp(op, items[0]);
2111 std::reverse(items.begin(), items.end());
2118 PatternRewriter &rewriter) {
2134ParseResult EnumConstantOp::parse(OpAsmParser &parser, OperationState &result) {
2141 auto loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());
2142 if (parser.parseKeyword(&field) || parser.parseColonType(type))
2145 auto fieldAttr = EnumFieldAttr::get(
2146 loc, StringAttr::get(parser.getContext(), field), type);
2151 result.addAttribute(
"field", fieldAttr);
2152 result.addTypes(type);
2157void EnumConstantOp::print(OpAsmPrinter &p) {
2158 p <<
" " << getField().getField().getValue() <<
" : "
2159 << getField().getType().getValue();
2162void EnumConstantOp::getAsmResultNames(
2163 function_ref<
void(Value, StringRef)> setNameFn) {
2164 setNameFn(getResult(), getField().getField().str());
2167void EnumConstantOp::build(OpBuilder &builder, OperationState &odsState,
2168 EnumFieldAttr field) {
2169 return build(builder, odsState, field.getType().getValue(), field);
2172OpFoldResult EnumConstantOp::fold(FoldAdaptor adaptor) {
2173 assert(adaptor.getOperands().empty() &&
"constant has no operands");
2174 return getFieldAttr();
2177LogicalResult EnumConstantOp::verify() {
2178 auto fieldAttr = getFieldAttr();
2179 auto fieldType = fieldAttr.getType().getValue();
2182 if (fieldType != getType())
2183 emitOpError(
"return type ")
2184 << getType() <<
" does not match attribute type " << fieldAttr;
2192LogicalResult EnumCmpOp::verify() {
2194 auto lhsType = type_cast<EnumType>(getLhs().getType());
2195 auto rhsType = type_cast<EnumType>(getRhs().getType());
2196 if (rhsType != lhsType)
2197 emitOpError(
"types do not match");
2205ParseResult StructCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2206 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2207 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
2208 Type declOrAliasType;
2210 if (parser.parseLParen() || parser.parseOperandList(operands) ||
2211 parser.parseRParen() || parser.parseOptionalAttrDict(result.attributes) ||
2212 parser.parseColonType(declOrAliasType))
2215 auto declType = type_dyn_cast<StructType>(declOrAliasType);
2217 return parser.emitError(parser.getNameLoc(),
2218 "expected !hw.struct type or alias");
2220 llvm::SmallVector<Type, 4> structInnerTypes;
2221 declType.getInnerTypes(structInnerTypes);
2222 result.addTypes(declOrAliasType);
2224 if (parser.resolveOperands(operands, structInnerTypes, inputOperandsLoc,
2230void StructCreateOp::print(OpAsmPrinter &printer) {
2232 printer.printOperands(getInput());
2234 printer.printOptionalAttrDict((*this)->getAttrs());
2235 printer <<
" : " << getType();
2238LogicalResult StructCreateOp::verify() {
2239 auto elements = hw::type_cast<StructType>(getType()).getElements();
2241 if (elements.size() != getInput().size())
2242 return emitOpError(
"structure field count mismatch");
2244 for (
const auto &[field, value] :
llvm::zip(elements, getInput()))
2245 if (field.type != value.getType())
2246 return emitOpError(
"structure field `")
2247 << field.name <<
"` type does not match";
2252OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
2254 if (!getInput().
empty())
2255 if (
auto explodeOp = getInput()[0].getDefiningOp<StructExplodeOp>();
2256 explodeOp && getInput() == explodeOp.getResults() &&
2257 getResult().getType() == explodeOp.getInput().getType())
2258 return explodeOp.getInput();
2260 auto inputs = adaptor.getInput();
2261 if (llvm::any_of(inputs, [](Attribute attr) {
2262 return !isa_and_nonnull<IntegerAttr>(attr);
2265 return ArrayAttr::get(getContext(), inputs);
2272ParseResult StructExplodeOp::parse(OpAsmParser &parser,
2273 OperationState &result) {
2274 OpAsmParser::UnresolvedOperand operand;
2277 if (parser.parseOperand(operand) ||
2278 parser.parseOptionalAttrDict(result.attributes) ||
2279 parser.parseColonType(declType))
2281 auto structType = type_dyn_cast<StructType>(declType);
2283 return parser.emitError(parser.getNameLoc(),
2284 "invalid kind of type specified");
2286 llvm::SmallVector<Type, 4> structInnerTypes;
2287 structType.getInnerTypes(structInnerTypes);
2288 result.addTypes(structInnerTypes);
2290 if (parser.resolveOperand(operand, declType, result.operands))
2295void StructExplodeOp::print(OpAsmPrinter &printer) {
2297 printer.printOperand(getInput());
2298 printer.printOptionalAttrDict((*this)->getAttrs());
2299 printer <<
" : " << getInput().getType();
2302LogicalResult StructExplodeOp::fold(FoldAdaptor adaptor,
2303 SmallVectorImpl<OpFoldResult> &results) {
2304 auto input = adaptor.getInput();
2307 llvm::copy(cast<ArrayAttr>(input), std::back_inserter(results));
2311LogicalResult StructExplodeOp::canonicalize(StructExplodeOp op,
2312 PatternRewriter &rewriter) {
2313 auto *inputOp = op.getInput().getDefiningOp();
2314 auto elements = type_cast<StructType>(op.getInput().getType()).getElements();
2315 auto result = failure();
2316 auto opResults = op.getResults();
2317 for (uint32_t index = 0; index < elements.size(); index++) {
2319 rewriter.replaceAllUsesWith(opResults[index], foldResult);
2326void StructExplodeOp::getAsmResultNames(
2327 function_ref<
void(Value, StringRef)> setNameFn) {
2328 auto structType = type_cast<StructType>(getInput().getType());
2329 for (
auto [res, field] :
llvm::zip(getResults(), structType.getElements()))
2330 setNameFn(res, field.name.str());
2333void StructExplodeOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2335 StructType inputType = dyn_cast<StructType>(input.getType());
2337 SmallVector<Type, 16> fieldTypes;
2338 for (
auto field : inputType.getElements())
2339 fieldTypes.push_back(field.type);
2340 build(odsBuilder, odsState, fieldTypes, input);
2349template <
typename AggregateOp,
typename AggregateType>
2351 AggregateType aggType,
2353 auto index = op.getFieldIndex();
2354 if (index >= aggType.getElements().size())
2355 return op.emitOpError() <<
"field index " << index
2356 <<
" exceeds element count of aggregate type";
2360 return op.emitOpError()
2361 <<
"type " << aggType.getElements()[index].type
2362 <<
" of accessed field in aggregate at index " << index
2363 <<
" does not match expected type " <<
elementType;
2368LogicalResult StructExtractOp::verify() {
2369 return verifyAggregateFieldIndexAndType<StructExtractOp, StructType>(
2370 *
this, getInput().getType(), getType());
2375template <
typename AggregateType>
2377 OpAsmParser::UnresolvedOperand operand;
2378 StringAttr fieldName;
2381 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2382 parser.parseAttribute(fieldName) || parser.parseRSquare() ||
2383 parser.parseOptionalAttrDict(result.attributes) ||
2384 parser.parseColonType(declType))
2386 auto aggType = type_dyn_cast<AggregateType>(declType);
2388 return parser.emitError(parser.getNameLoc(),
2389 "invalid kind of type specified");
2391 auto fieldIndex = aggType.getFieldIndex(fieldName);
2393 parser.emitError(parser.getNameLoc(),
"field name '" +
2394 fieldName.getValue() +
2395 "' not found in aggregate type");
2400 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2401 result.addAttribute(
"fieldIndex", indexAttr);
2402 Type resultType = aggType.getElements()[*fieldIndex].type;
2403 result.addTypes(resultType);
2405 if (parser.resolveOperand(operand, declType, result.operands))
2412template <
typename AggType>
2415 printer.printOperand(op.getInput());
2416 printer <<
"[\"" << op.getFieldName() <<
"\"]";
2417 printer.printOptionalAttrDict(op->getAttrs(), {
"fieldIndex"});
2418 printer <<
" : " << op.getInput().getType();
2421ParseResult StructExtractOp::parse(OpAsmParser &parser,
2422 OperationState &result) {
2423 return parseExtractOp<StructType>(parser, result);
2426void StructExtractOp::print(OpAsmPrinter &printer) {
2430void StructExtractOp::build(OpBuilder &builder, OperationState &odsState,
2431 Value input, StructType::FieldInfo field) {
2433 type_cast<StructType>(input.getType()).getFieldIndex(field.name);
2434 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2435 build(builder, odsState, field.type, input, *fieldIndex);
2438void StructExtractOp::build(OpBuilder &builder, OperationState &odsState,
2439 Value input, StringAttr fieldName) {
2440 auto structType = type_cast<StructType>(input.getType());
2441 auto fieldIndex = structType.getFieldIndex(fieldName);
2442 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2443 auto resultType = structType.getElements()[*fieldIndex].type;
2444 build(builder, odsState, resultType, input, *fieldIndex);
2447OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
2448 if (
auto constOperand = adaptor.getInput()) {
2450 auto operandAttr = llvm::cast<ArrayAttr>(constOperand);
2451 return operandAttr.getValue()[getFieldIndex()];
2454 if (
auto foldResult =
2461 PatternRewriter &rewriter) {
2462 auto *inputOp = op.getInput().getDefiningOp();
2465 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
2466 if (structInject.getFieldIndex() != op.getFieldIndex()) {
2468 op, op.getType(), structInject.getInput(), op.getFieldIndexAttr());
2476void StructExtractOp::getAsmResultNames(
2477 function_ref<
void(Value, StringRef)> setNameFn) {
2485void StructInjectOp::build(OpBuilder &builder, OperationState &odsState,
2486 Value input, StringAttr fieldName, Value newValue) {
2487 auto structType = type_cast<StructType>(input.getType());
2488 auto fieldIndex = structType.getFieldIndex(fieldName);
2489 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2490 build(builder, odsState, input, *fieldIndex, newValue);
2493LogicalResult StructInjectOp::verify() {
2494 return verifyAggregateFieldIndexAndType<StructInjectOp, StructType>(
2495 *
this, getInput().getType(), getNewValue().getType());
2498ParseResult StructInjectOp::parse(OpAsmParser &parser, OperationState &result) {
2499 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2500 OpAsmParser::UnresolvedOperand operand, val;
2501 StringAttr fieldName;
2504 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2505 parser.parseAttribute(fieldName) || parser.parseRSquare() ||
2506 parser.parseComma() || parser.parseOperand(val) ||
2507 parser.parseOptionalAttrDict(result.attributes) ||
2508 parser.parseColonType(declType))
2510 auto structType = type_dyn_cast<StructType>(declType);
2512 return parser.emitError(inputOperandsLoc,
"invalid kind of type specified");
2514 auto fieldIndex = structType.getFieldIndex(fieldName);
2516 parser.emitError(parser.getNameLoc(),
"field name '" +
2517 fieldName.getValue() +
2518 "' not found in aggregate type");
2523 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2524 result.addAttribute(
"fieldIndex", indexAttr);
2525 result.addTypes(declType);
2527 Type resultType = structType.getElements()[*fieldIndex].type;
2528 if (parser.resolveOperands({operand, val}, {declType, resultType},
2529 inputOperandsLoc, result.operands))
2534void StructInjectOp::print(OpAsmPrinter &printer) {
2536 printer.printOperand(getInput());
2538 printer.printOperand(getNewValue());
2539 printer.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
2540 printer <<
" : " << getInput().getType();
2543OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
2544 auto input = adaptor.getInput();
2545 auto newValue = adaptor.getNewValue();
2546 if (!input || !newValue)
2548 SmallVector<Attribute> array;
2549 llvm::copy(cast<ArrayAttr>(input), std::back_inserter(array));
2550 array[getFieldIndex()] = newValue;
2551 return ArrayAttr::get(getContext(), array);
2554LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
2555 PatternRewriter &rewriter) {
2559 if (op->hasOneUse()) {
2560 auto &use = *op->use_begin();
2561 if (isa<StructInjectOp>(use.getOwner()) && use.getOperandNumber() == 0)
2566 SmallPtrSet<Operation *, 4> injects;
2567 DenseMap<StringAttr, Value> fields;
2570 StructInjectOp inject = op;
2573 if (!injects.insert(inject).second)
2576 fields.try_emplace(inject.getFieldNameAttr(), inject.getNewValue());
2577 input = inject.getInput();
2578 inject = dyn_cast_or_null<StructInjectOp>(input.getDefiningOp());
2580 assert(input &&
"missing input to inject chain");
2582 auto ty = hw::type_cast<StructType>(op.getType());
2583 auto elements = ty.getElements();
2586 if (fields.size() == elements.size()) {
2587 SmallVector<Value> createFields;
2588 for (
const auto &field : elements) {
2589 auto it = fields.find(field.name);
2590 assert(it != fields.end() &&
"missing field");
2591 createFields.push_back(it->second);
2593 rewriter.replaceOpWithNewOp<
StructCreateOp>(op, ty, createFields);
2598 if (injects.size() == fields.size())
2602 for (uint32_t fieldIndex = 0; fieldIndex < elements.size(); fieldIndex++) {
2603 auto it = fields.find(elements[fieldIndex].name);
2604 if (it == fields.end())
2606 input = StructInjectOp::create(rewriter, op.getLoc(), ty, input, fieldIndex,
2610 rewriter.replaceOp(op, input);
2618LogicalResult UnionCreateOp::verify() {
2619 return verifyAggregateFieldIndexAndType<UnionCreateOp, UnionType>(
2620 *
this, getType(), getInput().getType());
2623void UnionCreateOp::build(OpBuilder &builder, OperationState &odsState,
2624 Type unionType, StringAttr fieldName, Value input) {
2625 auto fieldIndex = type_cast<UnionType>(unionType).getFieldIndex(fieldName);
2626 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2627 build(builder, odsState, unionType, *fieldIndex, input);
2630ParseResult UnionCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2631 Type declOrAliasType;
2632 StringAttr fieldName;
2633 OpAsmParser::UnresolvedOperand input;
2634 llvm::SMLoc fieldLoc = parser.getCurrentLocation();
2636 if (parser.parseAttribute(fieldName) || parser.parseComma() ||
2637 parser.parseOperand(input) ||
2638 parser.parseOptionalAttrDict(result.attributes) ||
2639 parser.parseColonType(declOrAliasType))
2642 auto declType = type_dyn_cast<UnionType>(declOrAliasType);
2644 return parser.emitError(parser.getNameLoc(),
2645 "expected !hw.union type or alias");
2647 auto fieldIndex = declType.getFieldIndex(fieldName);
2649 parser.emitError(fieldLoc,
"cannot find union field '")
2650 << fieldName.getValue() <<
'\'';
2655 IntegerAttr::get(IntegerType::get(parser.getContext(), 32), *fieldIndex);
2656 result.addAttribute(
"fieldIndex", indexAttr);
2657 Type inputType = declType.getElements()[*fieldIndex].type;
2659 if (parser.resolveOperand(input, inputType, result.operands))
2661 result.addTypes({declOrAliasType});
2665void UnionCreateOp::print(OpAsmPrinter &printer) {
2667 printer.printOperand(getInput());
2668 printer.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
2669 printer <<
" : " << getType();
2676ParseResult UnionExtractOp::parse(OpAsmParser &parser, OperationState &result) {
2677 return parseExtractOp<UnionType>(parser, result);
2680void UnionExtractOp::print(OpAsmPrinter &printer) {
2684LogicalResult UnionExtractOp::inferReturnTypes(
2685 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
2686 DictionaryAttr attrs, mlir::OpaqueProperties properties,
2687 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2688 Adaptor adaptor(operands, attrs, properties, regions);
2689 auto unionElements =
2690 hw::type_cast<UnionType>((adaptor.getInput().getType())).getElements();
2691 unsigned fieldIndex = adaptor.getFieldIndexAttr().getValue().getZExtValue();
2692 if (fieldIndex >= unionElements.size()) {
2694 mlir::emitError(*loc,
"field index " + Twine(fieldIndex) +
2695 " exceeds element count of aggregate type");
2698 results.push_back(unionElements[fieldIndex].type);
2702void UnionExtractOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2703 Value input, StringAttr fieldName) {
2704 auto unionType = type_cast<UnionType>(input.getType());
2705 auto fieldIndex = unionType.getFieldIndex(fieldName);
2706 assert(fieldIndex.has_value() &&
"field name not found in aggregate type");
2707 auto resultType = unionType.getElements()[*fieldIndex].type;
2708 build(odsBuilder, odsState, resultType, input, *fieldIndex);
2720OpFoldResult ArrayGetOp::fold(FoldAdaptor adaptor) {
2721 auto inputCst = dyn_cast_or_null<ArrayAttr>(adaptor.getInput());
2722 auto indexCst = dyn_cast_or_null<IntegerAttr>(adaptor.getIndex());
2727 auto indexVal = indexCst.getValue();
2728 if (indexVal.getBitWidth() < 64) {
2729 auto index = indexVal.getZExtValue();
2730 return inputCst[inputCst.size() - 1 - index];
2735 if (!inputCst.empty() && llvm::all_equal(inputCst))
2740 if (
auto bitcast = getInput().getDefiningOp<hw::BitcastOp>()) {
2741 auto intTy = dyn_cast<IntegerType>(getType());
2744 auto bitcastInputOp = bitcast.getInput().getDefiningOp<
hw::ConstantOp>();
2745 if (!bitcastInputOp)
2749 auto bitcastInputCst = bitcastInputOp.getValue();
2752 auto startIdx = indexCst.getValue().zext(bitcastInputCst.getBitWidth()) *
2753 getType().getIntOrFloatBitWidth();
2755 return IntegerAttr::get(intTy, bitcastInputCst.lshr(startIdx).trunc(
2756 intTy.getIntOrFloatBitWidth()));
2760 if (
auto inject = getInput().getDefiningOp<ArrayInjectOp>())
2761 if (getIndex() == inject.getIndex())
2762 return inject.getElement();
2764 auto inputCreate = getInput().getDefiningOp<
ArrayCreateOp>();
2768 if (
auto uniformValue = inputCreate.getUniformElement())
2769 return uniformValue;
2771 if (!indexCst || indexCst.getValue().getBitWidth() > 64)
2774 uint64_t index = indexCst.getValue().getLimitedValue();
2775 auto createInputs = inputCreate.getInputs();
2776 if (index >= createInputs.size())
2778 return createInputs[createInputs.size() - index - 1];
2781LogicalResult ArrayGetOp::canonicalize(
ArrayGetOp op,
2782 PatternRewriter &rewriter) {
2787 auto *inputOp = op.getInput().getDefiningOp();
2788 if (
auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
2790 auto offsetOp = inputSlice.getLowIndex();
2795 uint64_t offset = *offsetOpt + *idxOpt;
2798 rewriter.replaceOpWithNewOp<
ArrayGetOp>(op, inputSlice.getInput(),
2803 if (
auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
2805 uint64_t elemIndex = *idxOpt;
2806 for (
auto input :
llvm::reverse(inputConcat.getInputs())) {
2807 size_t size = hw::type_cast<ArrayType>(input.getType()).getNumElements();
2808 if (elemIndex >= size) {
2813 unsigned indexWidth = size == 1 ? 1 : llvm::Log2_64_Ceil(size);
2816 rewriter.getIntegerType(indexWidth), elemIndex);
2818 rewriter.replaceOpWithNewOp<
ArrayGetOp>(op, input, newIdxOp);
2827 if (
auto innerGet = dyn_cast_or_null<hw::ArrayGetOp>(inputOp)) {
2832 SmallVector<Value> newValues;
2833 for (
auto operand : create.getOperands())
2834 newValues.push_back(rewriter.createOrFold<
hw::
ArrayGetOp>(
2835 op.
getLoc(), operand, op.getIndex()));
2840 innerGet.getIndex());
2853OpFoldResult ArrayInjectOp::fold(FoldAdaptor adaptor) {
2854 auto inputAttr = dyn_cast_or_null<ArrayAttr>(adaptor.getInput());
2855 auto indexAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getIndex());
2856 auto elementAttr = adaptor.getElement();
2859 if (inputAttr && indexAttr && elementAttr) {
2860 if (
auto index = indexAttr.getValue().tryZExtValue()) {
2861 if (*index < inputAttr.size()) {
2862 SmallVector<Attribute> elements(inputAttr.getValue());
2863 elements[inputAttr.size() - 1 - *index] = elementAttr;
2864 return ArrayAttr::get(getContext(), elements);
2873 PatternRewriter &rewriter) {
2877 if (op->hasOneUse()) {
2878 auto &use = *op->use_begin();
2879 if (isa<ArrayInjectOp>(use.getOwner()) && use.getOperandNumber() == 0)
2884 auto arrayLength = type_cast<ArrayType>(op.getType()).getNumElements();
2887 while (
auto inject = input.getDefiningOp<ArrayInjectOp>()) {
2890 if (!matchPattern(inject.getIndex(), mlir::m_ConstantInt(&indexAPInt)))
2892 if (indexAPInt.getActiveBits() > 32)
2894 uint32_t index = indexAPInt.getZExtValue();
2899 if (index < arrayLength)
2900 elements.insert({index, inject.getElement()});
2903 input = inject.getInput();
2910 if (elements.size() == arrayLength) {
2911 SmallVector<Value, 4> operands;
2912 operands.reserve(arrayLength);
2913 for (uint32_t idx = 0; idx < arrayLength; ++idx)
2914 operands.push_back(elements.at(arrayLength - idx - 1));
2915 rewriter.replaceOpWithNewOp<
ArrayCreateOp>(op, op.getType(), operands);
2924 auto createOp = op.getInput().getDefiningOp<
ArrayCreateOp>();
2930 if (!matchPattern(op.getIndex(), mlir::m_ConstantInt(&indexAPInt)) ||
2931 !indexAPInt.ult(createOp.getInputs().size()))
2935 SmallVector<Value> elements = createOp.getInputs();
2936 elements[elements.size() - indexAPInt.getZExtValue() - 1] = op.getElement();
2941void ArrayInjectOp::getCanonicalizationPatterns(RewritePatternSet &
patterns,
2952StringRef TypedeclOp::getPreferredName() {
2953 return getVerilogName().value_or(
getName());
2956Type TypedeclOp::getAliasType() {
2957 auto parentScope = cast<hw::TypeScopeOp>(getOperation()->getParentOp());
2958 return hw::TypeAliasType::get(
2959 SymbolRefAttr::get(parentScope.getSymNameAttr(),
2960 {FlatSymbolRefAttr::get(*this)}),
2968OpFoldResult BitcastOp::fold(FoldAdaptor) {
2971 if (getOperand().getType() == getType())
2972 return getOperand();
2977LogicalResult BitcastOp::canonicalize(
BitcastOp op, PatternRewriter &rewriter) {
2983 dyn_cast_or_null<BitcastOp>(op.getInput().getDefiningOp());
2986 auto bitcast = rewriter.createOrFold<
BitcastOp>(op.getLoc(), op.getType(),
2987 inputBitcast.getInput());
2988 rewriter.replaceOp(op, bitcast);
2992LogicalResult BitcastOp::verify() {
2994 return this->emitOpError(
"Bitwidth of input must match result");
3002bool HierPathOp::dropModule(StringAttr moduleToDrop) {
3003 SmallVector<Attribute, 4> newPath;
3004 bool updateMade =
false;
3005 for (
auto nameRef : getNamepath()) {
3007 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3008 if (ref.getModule() == moduleToDrop)
3011 newPath.push_back(ref);
3013 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == moduleToDrop)
3016 newPath.push_back(nameRef);
3020 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3024bool HierPathOp::inlineModule(StringAttr moduleToDrop) {
3025 SmallVector<Attribute, 4> newPath;
3026 bool updateMade =
false;
3027 StringRef inlinedInstanceName =
"";
3028 for (
auto nameRef : getNamepath()) {
3030 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3031 if (ref.getModule() == moduleToDrop) {
3032 inlinedInstanceName = ref.getName().getValue();
3034 }
else if (!inlinedInstanceName.empty()) {
3035 newPath.push_back(hw::InnerRefAttr::get(
3037 StringAttr::get(getContext(), inlinedInstanceName +
"_" +
3038 ref.getName().getValue())));
3039 inlinedInstanceName =
"";
3041 newPath.push_back(ref);
3043 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == moduleToDrop)
3046 newPath.push_back(nameRef);
3050 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3054bool HierPathOp::updateModule(StringAttr oldMod, StringAttr newMod) {
3055 SmallVector<Attribute, 4> newPath;
3056 bool updateMade =
false;
3057 for (
auto nameRef : getNamepath()) {
3059 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3060 if (ref.getModule() == oldMod) {
3061 newPath.push_back(hw::InnerRefAttr::get(newMod, ref.getName()));
3064 newPath.push_back(ref);
3066 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == oldMod) {
3067 newPath.push_back(FlatSymbolRefAttr::get(newMod));
3070 newPath.push_back(nameRef);
3074 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3078bool HierPathOp::updateModuleAndInnerRef(
3079 StringAttr oldMod, StringAttr newMod,
3080 const llvm::DenseMap<StringAttr, StringAttr> &innerSymRenameMap) {
3081 auto fromRef = FlatSymbolRefAttr::get(oldMod);
3082 if (oldMod == newMod)
3085 auto namepathNew = getNamepath().getValue().vec();
3086 bool updateMade =
false;
3088 for (
auto &element : namepathNew) {
3089 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(element)) {
3090 if (innerRef.getModule() != oldMod)
3092 auto symName = innerRef.getName();
3095 auto to = innerSymRenameMap.find(symName);
3096 if (to != innerSymRenameMap.end())
3097 symName = to->second;
3099 element = hw::InnerRefAttr::get(newMod, symName);
3102 if (element != fromRef)
3106 element = FlatSymbolRefAttr::get(newMod);
3110 setNamepathAttr(ArrayAttr::get(getContext(), namepathNew));
3114bool HierPathOp::truncateAtModule(StringAttr atMod,
bool includeMod) {
3115 SmallVector<Attribute, 4> newPath;
3116 bool updateMade =
false;
3117 for (
auto nameRef : getNamepath()) {
3119 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3120 if (ref.getModule() == atMod) {
3123 newPath.push_back(ref);
3125 newPath.push_back(ref);
3127 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == atMod && !includeMod)
3130 newPath.push_back(nameRef);
3136 setNamepathAttr(ArrayAttr::get(getContext(), newPath));
3141StringAttr HierPathOp::modPart(
unsigned i) {
3142 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3143 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
3144 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
3148StringAttr HierPathOp::root() {
3154bool HierPathOp::hasModule(StringAttr modName) {
3155 for (
auto nameRef : getNamepath()) {
3157 if (
auto ref = dyn_cast<hw::InnerRefAttr>(nameRef)) {
3158 if (ref.getModule() == modName)
3161 if (cast<FlatSymbolRefAttr>(nameRef).getAttr() == modName)
3169bool HierPathOp::hasInnerSym(StringAttr modName, StringAttr symName)
const {
3170 for (
auto nameRef : const_cast<HierPathOp *>(this)->getNamepath())
3171 if (auto ref = dyn_cast<
hw::InnerRefAttr>(nameRef))
3172 if (ref.
getName() == symName && ref.getModule() == modName)
3180StringAttr HierPathOp::refPart(
unsigned i) {
3181 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3182 .Case<FlatSymbolRefAttr>([](
auto a) {
return StringAttr({}); })
3183 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getName(); });
3188StringAttr HierPathOp::ref() {
3190 return refPart(getNamepath().size() - 1);
3194StringAttr HierPathOp::leafMod() {
3196 return modPart(getNamepath().size() - 1);
3201bool HierPathOp::isModule() {
return !ref(); }
3205bool HierPathOp::isComponent() {
return (
bool)ref(); }
3221 ArrayAttr expectedModuleNames = {};
3222 auto checkExpectedModule = [&](Attribute name) -> LogicalResult {
3223 if (!expectedModuleNames)
3225 if (llvm::any_of(expectedModuleNames,
3226 [name](Attribute attr) {
return attr == name; }))
3228 auto diag = emitOpError() <<
"instance path is incorrect. Expected ";
3229 size_t n = expectedModuleNames.size();
3233 for (
size_t i = 0; i < n; ++i) {
3235 diag << ((i + 1 == n) ?
" or " :
", ");
3236 diag << cast<StringAttr>(expectedModuleNames[i]);
3238 diag <<
". Instead found: " << name;
3242 if (!getNamepath() || getNamepath().
empty())
3243 return emitOpError() <<
"the instance path cannot be empty";
3244 for (
unsigned i = 0, s = getNamepath().size() - 1; i <
s; ++i) {
3245 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(getNamepath()[i]);
3247 return emitOpError()
3248 <<
"the instance path can only contain inner sym reference"
3249 <<
", only the leaf can refer to a module symbol";
3251 if (failed(checkExpectedModule(innerRef.getModule())))
3254 auto instOp = ns.
lookupOp<igraph::InstanceOpInterface>(innerRef);
3256 return emitOpError() <<
" module: " << innerRef.getModule()
3257 <<
" does not contain any instance with symbol: "
3258 << innerRef.getName();
3259 expectedModuleNames = instOp.getReferencedModuleNamesAttr();
3263 auto leafRef = getNamepath()[getNamepath().size() - 1];
3264 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(leafRef)) {
3265 if (!ns.
lookup(innerRef)) {
3266 return emitOpError() <<
" operation with symbol: " << innerRef
3267 <<
" was not found ";
3269 if (failed(checkExpectedModule(innerRef.getModule())))
3271 }
else if (failed(checkExpectedModule(
3272 cast<FlatSymbolRefAttr>(leafRef).getAttr()))) {
3278void HierPathOp::print(OpAsmPrinter &p) {
3282 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
3283 if (
auto visibility =
3284 getOperation()->getAttrOfType<StringAttr>(visibilityAttrName))
3285 p << visibility.getValue() <<
' ';
3287 p.printSymbolName(getSymName());
3289 llvm::interleaveComma(getNamepath().getValue(), p, [&](Attribute attr) {
3290 if (
auto ref = dyn_cast<hw::InnerRefAttr>(attr)) {
3291 p.printSymbolName(ref.getModule().getValue());
3293 p.printSymbolName(ref.getName().getValue());
3295 p.printSymbolName(cast<FlatSymbolRefAttr>(attr).getValue());
3299 p.printOptionalAttrDict(
3300 (*this)->getAttrs(),
3301 {SymbolTable::getSymbolAttrName(),
"namepath", visibilityAttrName});
3304ParseResult HierPathOp::parse(OpAsmParser &parser, OperationState &result) {
3306 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
3310 if (parser.parseSymbolName(symName, SymbolTable::getSymbolAttrName(),
3315 SmallVector<Attribute> namepath;
3316 if (parser.parseCommaSeparatedList(
3317 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
3318 auto loc = parser.getCurrentLocation();
3320 if (parser.parseAttribute(ref))
3324 auto pathLength = ref.getNestedReferences().size();
3325 if (pathLength == 0)
3327 FlatSymbolRefAttr::get(ref.getRootReference()));
3328 else if (pathLength == 1)
3329 namepath.push_back(hw::InnerRefAttr::get(ref.getRootReference(),
3330 ref.getLeafReference()));
3332 return parser.emitError(loc,
3333 "only one nested reference is allowed");
3337 result.addAttribute(
"namepath",
3338 ArrayAttr::get(parser.getContext(), namepath));
3340 if (parser.parseOptionalAttrDict(result.attributes))
3350void TriggeredOp::build(OpBuilder &builder, OperationState &odsState,
3351 EventControlAttr event, Value trigger,
3352 ValueRange inputs) {
3353 odsState.addOperands(trigger);
3354 odsState.addOperands(inputs);
3355 odsState.addAttribute(getEventAttrName(odsState.name), event);
3356 auto *r = odsState.addRegion();
3360 llvm::SmallVector<Location> argLocs;
3361 llvm::transform(inputs, std::back_inserter(argLocs),
3362 [&](Value v) {
return v.getLoc(); });
3363 b->addArguments(inputs.getTypes(), argLocs);
3371#define GET_OP_CLASSES
3372#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)
void getAsmBlockArgumentNamesImpl(Operation *op, 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 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 bool flattenConcatOp(ArrayConcatOp op, PatternRewriter &rewriter)
static LogicalResult foldCreateToSlice(ArrayCreateOp op, PatternRewriter &rewriter)
static SmallVector< PortInfo > getPortList(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 printArrayConcatTypes(OpAsmPrinter &p, Operation *, TypeRange inputTypes, Type resultType)
static ParseResult parseSliceTypes(OpAsmParser &p, Type &srcType, Type &idxType)
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 bool mergeConcatSlices(ArrayConcatOp op, PatternRewriter &rewriter)
static SmallVector< Location > getAllPortLocs(ModTy module)
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 setAllPortNames(ArrayRef< Attribute > names, ModTy module)
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 void setHWModuleType(ModTy &mod, ModuleType type)
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 PortInfo getPort(ModuleTy &mod, size_t idx)
static void printSliceTypes(OpAsmPrinter &p, Operation *, Type srcType, Type idxType)
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 ParseResult parseArrayConcatTypes(OpAsmParser &p, SmallVectorImpl< Type > &inputTypes, Type &resultType)
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
A namespace that is used to store existing names and generate new names in some scope within the IR.
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
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)
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
This helps visit TypeOp nodes.
ResultType dispatchTypeOpVisitor(Operation *op, ExtraArgs... args)
ResultType visitUnhandledTypeOp(Operation *op, ExtraArgs... args)
This callback is invoked on any combinational operations that are not handled by the concrete visitor...
ResultType visitInvalidTypeOp(Operation *op, ExtraArgs... args)
This callback is invoked on any non-expression operations.
create(array_value, low_index, ret_type)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
uint64_t getWidth(Type t)
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
LogicalResult verifyParameterStructure(ArrayAttr parameters, ArrayAttr moduleParameters, const EmitErrorFn &emitError)
Check that all the parameter values specified to the instance are structurally valid.
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...
LogicalResult verifyInstanceOfHWModule(Operation *instance, FlatSymbolRefAttr moduleRef, OperandRange inputs, TypeRange results, ArrayAttr argNames, ArrayAttr resultNames, ArrayAttr parameters, SymbolTableCollection &symbolTable)
Combines verifyReferencedModule, verifyInputs, verifyOutputs, and verifyParameters.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
void printModuleSignatureNew(OpAsmPrinter &p, Region &body, hw::ModuleType modType, ArrayRef< Attribute > portAttrs, ArrayRef< Location > locAttrs)
bool isOffset(Value base, Value index, uint64_t offset)
llvm::function_ref< void(OpBuilder &, HWModulePortAccessor &)> HWModuleBuilder
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function 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...
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.
StringAttr getVerilogModuleNameAttr(Operation *module)
Returns the verilog module name attribute or symbol name of any module-like operations.
mlir::Type getCanonicalType(mlir::Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ParseResult parseInputPortList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inputs, SmallVectorImpl< Type > &inputTypes, ArrayAttr &inputNames)
Parse a list of instance input ports.
void printOutputPortList(OpAsmPrinter &p, Operation *op, TypeRange resultTypes, ArrayAttr resultNames)
Print a list of instance output ports.
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.
void printInputPortList(OpAsmPrinter &p, Operation *op, OperandRange inputs, TypeRange inputTypes, ArrayAttr inputNames)
Print a list of instance input ports.
ParseResult parseOutputPortList(OpAsmParser &parser, SmallVectorImpl< Type > &resultTypes, ArrayAttr &resultNames)
Parse a list of instance output ports.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
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.
PortInfo & at(size_t idx)
size_t sizeOutputs() const
size_t sizeInputs() const
PortDirectionRange getOutputs()
This holds the name, type, direction of a module's ports.