23 #include "mlir/IR/Builders.h"
24 #include "mlir/IR/PatternMatch.h"
25 #include "mlir/Interfaces/FunctionImplementation.h"
26 #include "llvm/ADT/BitVector.h"
27 #include "llvm/ADT/SmallPtrSet.h"
28 #include "llvm/ADT/StringSet.h"
30 using namespace circt;
32 using mlir::TypedAttr;
44 llvm_unreachable(
"unknown PortDirection");
48 hw::ArrayType arrayType =
50 assert(arrayType &&
"expected array type");
51 unsigned indexWidth = index.getType().getIntOrFloatBitWidth();
52 auto requiredWidth = llvm::Log2_64_Ceil(arrayType.getNumElements());
53 return requiredWidth == 0 ? (indexWidth == 0 || indexWidth == 1)
54 : indexWidth == requiredWidth;
59 struct IsCombClassifier :
public TypeOpVisitor<IsCombClassifier, bool> {
60 bool visitInvalidTypeOp(Operation *op) {
return false; }
61 bool visitUnhandledTypeOp(Operation *op) {
return true; }
64 return (op->getDialect() && op->getDialect()->getNamespace() ==
"comb") ||
70 if (
auto structCreate = dyn_cast_or_null<StructCreateOp>(inputOp)) {
71 auto ty = type_cast<StructType>(structCreate.getResult().getType());
72 if (
auto idx = ty.getFieldIndex(field))
73 return structCreate.getOperand(*idx);
77 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
78 if (structInject.getField() != field)
80 return structInject.getNewValue();
86 ArrayRef<Attribute> attrs) {
91 if (a && !cast<DictionaryAttr>(a).
empty()) {
108 auto module = cast<HWModuleOp>(region.getParentOp());
110 auto *block = ®ion.front();
111 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
112 auto name = module.getInputName(i);
114 setNameFn(block->getArgument(i), name);
131 Attribute value, ArrayAttr moduleParameters,
133 bool disallowParamRefs) {
136 if (value.isa<IntegerAttr>() || value.isa<FloatAttr>() ||
137 value.isa<StringAttr>() || value.isa<ParamVerbatimAttr>())
141 if (
auto expr = value.dyn_cast<ParamExprAttr>()) {
142 for (
auto op : expr.getOperands())
151 if (
auto parameterRef = value.dyn_cast<ParamDeclRefAttr>()) {
152 auto nameAttr = parameterRef.getName();
156 if (disallowParamRefs) {
157 instanceError([&](
auto &diag) {
158 diag <<
"parameter " << nameAttr
159 <<
" cannot be used as a default value for a parameter";
166 for (
auto param : moduleParameters) {
167 auto paramAttr = param.cast<ParamDeclAttr>();
168 if (paramAttr.getName() != nameAttr)
172 if (paramAttr.getType() == parameterRef.getType())
175 instanceError([&](
auto &diag) {
176 diag <<
"parameter " << nameAttr <<
" used with type "
177 << parameterRef.getType() <<
"; should have type "
178 << paramAttr.getType();
184 instanceError([&](
auto &diag) {
185 diag <<
"use of unknown parameter " << nameAttr;
191 instanceError([&](
auto &diag) {
192 diag <<
"invalid parameter value " << value;
206 bool disallowParamRefs) {
208 [&](
const std::function<bool(InFlightDiagnostic &)> &fn) {
210 auto diag = usingOp->emitOpError();
212 diag.attachNote(module->getLoc()) <<
"module declared here";
217 module->getAttrOfType<ArrayAttr>(
"parameters"),
218 emitError, disallowParamRefs);
232 for (
auto [i, barg] : llvm::enumerate(bodyRegion.getArguments())) {
264 void ConstantOp::print(OpAsmPrinter &p) {
266 p.printAttribute(getValueAttr());
267 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
270 ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
271 IntegerAttr valueAttr;
273 if (parser.parseAttribute(valueAttr,
"value", result.attributes) ||
274 parser.parseOptionalAttrDict(result.attributes))
277 result.addTypes(valueAttr.getType());
281 LogicalResult ConstantOp::verify() {
283 if (getValue().
getBitWidth() != getType().cast<IntegerType>().getWidth())
285 "hw.constant attribute bitwidth doesn't match return type");
292 void ConstantOp::build(OpBuilder &
builder, OperationState &result,
293 const APInt &value) {
296 auto attr =
builder.getIntegerAttr(type, value);
297 return build(
builder, result, type, attr);
302 void ConstantOp::build(OpBuilder &
builder, OperationState &result,
304 return build(
builder, result, value.getType(), value);
311 void ConstantOp::build(OpBuilder &
builder, OperationState &result, Type type,
313 auto numBits = type.cast<IntegerType>().getWidth();
314 build(
builder, result, APInt(numBits, (uint64_t)value,
true));
318 function_ref<
void(Value, StringRef)> setNameFn) {
319 auto intTy = getType();
320 auto intCst = getValue();
323 if (intTy.cast<IntegerType>().getWidth() == 1)
324 return setNameFn(getResult(), intCst.isZero() ?
"false" :
"true");
327 SmallVector<char, 32> specialNameBuffer;
328 llvm::raw_svector_ostream specialName(specialNameBuffer);
329 specialName <<
'c' << intCst <<
'_' << intTy;
330 setNameFn(getResult(), specialName.str());
333 OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
334 assert(adaptor.getOperands().empty() &&
"constant has no operands");
335 return getValueAttr();
346 ArrayRef<StringRef> ignoredAttrs = {}) {
347 auto names = op.getAttributeNames();
348 llvm::SmallDenseSet<StringRef> nameSet;
349 nameSet.reserve(names.size() + ignoredAttrs.size());
350 nameSet.insert(names.begin(), names.end());
351 nameSet.insert(ignoredAttrs.begin(), ignoredAttrs.end());
352 return llvm::any_of(op->getAttrs(), [&](
auto namedAttr) {
353 return !nameSet.contains(namedAttr.getName());
359 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
360 if (!nameAttr.getValue().empty())
361 setNameFn(getResult(), nameAttr.getValue());
364 std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
366 OpFoldResult WireOp::fold(FoldAdaptor adaptor) {
375 LogicalResult WireOp::canonicalize(WireOp wire, PatternRewriter &rewriter) {
381 if (wire.getInnerSymAttr())
386 if (
auto *inputOp = wire.getInput().getDefiningOp()) {
387 auto name = wire.getNameAttr();
388 if (!name || name.getValue().empty())
389 name = wire->getAttrOfType<StringAttr>(
"sv.namehint");
391 rewriter.updateRootInPlace(
392 inputOp, [&] { inputOp->setAttr(
"sv.namehint", name); });
395 rewriter.replaceOp(wire, wire.getInput());
405 if (
auto typeAlias = type.dyn_cast<TypeAliasType>())
406 type = typeAlias.getCanonicalType();
408 if (
auto structType = type.dyn_cast<StructType>()) {
409 auto arrayAttr = attr.dyn_cast<ArrayAttr>();
411 return op->emitOpError(
"expected array attribute for constant of type ")
413 for (
auto [attr, fieldInfo] :
414 llvm::zip(arrayAttr.getValue(), structType.getElements())) {
418 }
else if (
auto arrayType = type.dyn_cast<ArrayType>()) {
419 auto arrayAttr = attr.dyn_cast<ArrayAttr>();
421 return op->emitOpError(
"expected array attribute for constant of type ")
424 for (
auto attr : arrayAttr.getValue()) {
428 }
else if (
auto arrayType = type.dyn_cast<UnpackedArrayType>()) {
429 auto arrayAttr = attr.dyn_cast<ArrayAttr>();
431 return op->emitOpError(
"expected array attribute for constant of type ")
434 for (
auto attr : arrayAttr.getValue()) {
438 }
else if (
auto enumType = type.dyn_cast<EnumType>()) {
439 auto stringAttr = attr.dyn_cast<StringAttr>();
441 return op->emitOpError(
"expected string attribute for constant of type ")
443 }
else if (
auto intType = type.dyn_cast<IntegerType>()) {
445 auto intAttr = attr.dyn_cast<IntegerAttr>();
447 return op->emitOpError(
"expected integer attribute for constant of type ")
450 if (intAttr.getValue().getBitWidth() != intType.getWidth())
451 return op->emitOpError(
"hw.constant attribute bitwidth "
452 "doesn't match return type");
454 return op->emitOpError(
"unknown element type") << type;
459 LogicalResult AggregateConstantOp::verify() {
463 OpFoldResult AggregateConstantOp::fold(FoldAdaptor) {
return getFieldsAttr(); }
471 if (p.parseType(resultType) || p.parseEqual() ||
472 p.parseAttribute(value, resultType))
479 p << resultType <<
" = ";
480 p.printAttributeWithoutType(value);
483 LogicalResult ParamValueOp::verify() {
486 getValue(), (*this)->getParentOfType<hw::HWModuleOp>(), *
this);
489 OpFoldResult ParamValueOp::fold(FoldAdaptor adaptor) {
490 assert(adaptor.getOperands().empty() &&
"hw.param.value has no operands");
491 return getValueAttr();
500 return isa<HWModuleLike, InstanceOp>(moduleOrInstance);
506 if (
auto instance = dyn_cast<InstanceOp>(moduleOrInstance)) {
507 SmallVector<Type>
inputs(instance->getOperandTypes());
508 SmallVector<Type> results(instance->getResultTypes());
512 if (
auto mod = dyn_cast<HWTestModuleOp>(moduleOrInstance))
513 return mod.getModuleType().getFuncType();
515 if (
auto mod = dyn_cast<HWModuleLike>(moduleOrInstance))
516 return mod.getHWModuleType().getFuncType();
518 return cast<mlir::FunctionOpInterface>(moduleOrInstance)
520 .cast<FunctionType>();
527 auto nameAttr = module->getAttrOfType<StringAttr>(
"verilogName");
531 return module->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
537 template <
typename ModuleTy>
540 const ModulePortInfo &ports, ArrayAttr parameters,
541 ArrayRef<NamedAttribute> attributes, StringAttr comment) {
542 using namespace mlir::function_interface_impl;
543 LocationAttr unknownLoc =
builder.getUnknownLoc();
546 result.addAttribute(SymbolTable::getSymbolAttrName(), name);
548 SmallVector<Attribute> argNames, resultNames;
549 SmallVector<Type, 4> argTypes, resultTypes;
550 SmallVector<Attribute> portAttrs;
551 SmallVector<Attribute> portLocs;
552 SmallVector<ModulePort> portTypes;
555 for (
auto elt : ports.getInputs()) {
556 portTypes.push_back(elt);
560 argTypes.push_back(elt.type);
561 argNames.push_back(elt.name);
562 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
564 if (elt.sym && !elt.sym.empty())
565 attr =
builder.getDictionaryAttr({{exportPortIdent, elt.sym}});
567 attr =
builder.getDictionaryAttr({});
568 portAttrs.push_back(attr);
571 for (
auto elt : ports.getOutputs()) {
572 portTypes.push_back(elt);
573 resultTypes.push_back(elt.type);
574 resultNames.push_back(elt.name);
575 portLocs.push_back(elt.loc ? elt.loc : unknownLoc);
577 if (elt.sym && !elt.sym.empty())
578 attr =
builder.getDictionaryAttr({{exportPortIdent, elt.sym}});
580 attr =
builder.getDictionaryAttr({});
581 portAttrs.push_back(attr);
586 parameters =
builder.getArrayAttr({});
590 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name),
592 result.addAttribute(
"portLocs",
builder.getArrayAttr(portLocs));
593 result.addAttribute(
"per_port_attrs",
595 result.addAttribute(
"parameters", parameters);
597 comment =
builder.getStringAttr(
"");
598 result.addAttribute(
"comment", comment);
599 result.addAttributes(attributes);
605 MLIRContext *context, ArrayRef<std::pair<unsigned, PortInfo>> insertArgs,
606 ArrayRef<unsigned> removeArgs, ArrayRef<Attribute> oldArgNames,
607 ArrayRef<Type> oldArgTypes, ArrayRef<Attribute> oldArgAttrs,
608 ArrayRef<Location> oldArgLocs, SmallVector<Attribute> &newArgNames,
609 SmallVector<Type> &newArgTypes, SmallVector<Attribute> &newArgAttrs,
610 SmallVector<Location> &newArgLocs, Block *body =
nullptr) {
615 assert(llvm::is_sorted(insertArgs,
616 [](
auto &a,
auto &b) {
return a.first < b.first; }) &&
617 "insertArgs must be in ascending order");
618 assert(llvm::is_sorted(removeArgs, [](
auto &a,
auto &b) {
return a < b; }) &&
619 "removeArgs must be in ascending order");
622 auto oldArgCount = oldArgTypes.size();
623 auto newArgCount = oldArgCount + insertArgs.size() - removeArgs.size();
624 assert((
int)newArgCount >= 0);
626 newArgNames.reserve(newArgCount);
627 newArgTypes.reserve(newArgCount);
628 newArgAttrs.reserve(newArgCount);
629 newArgLocs.reserve(newArgCount);
635 BitVector erasedIndices;
637 erasedIndices.resize(oldArgCount + insertArgs.size());
639 for (
unsigned argIdx = 0, idx = 0; argIdx <= oldArgCount; ++argIdx, ++idx) {
641 while (!insertArgs.empty() && insertArgs[0].first == argIdx) {
642 auto port = insertArgs[0].second;
647 (port.sym && !port.sym.empty())
650 newArgNames.push_back(port.name);
651 newArgTypes.push_back(port.type);
652 newArgAttrs.push_back(attr);
653 insertArgs = insertArgs.drop_front();
654 LocationAttr loc = port.loc ? port.loc : unknownLoc;
655 newArgLocs.push_back(loc);
657 body->insertArgument(idx++, port.type, loc);
659 if (argIdx == oldArgCount)
663 bool removed =
false;
664 while (!removeArgs.empty() && removeArgs[0] == argIdx) {
665 removeArgs = removeArgs.drop_front();
671 erasedIndices.set(idx);
673 newArgNames.push_back(oldArgNames[argIdx]);
674 newArgTypes.push_back(oldArgTypes[argIdx]);
675 newArgAttrs.push_back(oldArgAttrs.empty() ? emptyDictAttr
676 : oldArgAttrs[argIdx]);
677 newArgLocs.push_back(oldArgLocs[argIdx]);
682 body->eraseArguments(erasedIndices);
684 assert(newArgNames.size() == newArgCount);
685 assert(newArgTypes.size() == newArgCount);
686 assert(newArgAttrs.size() == newArgCount);
687 assert(newArgLocs.size() == newArgCount);
697 Operation *op, ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
698 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
699 ArrayRef<unsigned> removeInputs, ArrayRef<unsigned> removeOutputs,
701 auto moduleOp = cast<HWModuleLike>(op);
702 auto *context = moduleOp.getContext();
705 auto oldArgNames = moduleOp.getInputNames();
706 auto oldArgTypes = moduleOp.getInputTypes();
707 auto oldArgAttrs = moduleOp.getAllInputAttrs();
708 auto oldArgLocs = moduleOp.getInputLocs();
710 auto oldResultNames = moduleOp.getOutputNames();
711 auto oldResultTypes = moduleOp.getOutputTypes();
712 auto oldResultAttrs = moduleOp.getAllOutputAttrs();
713 auto oldResultLocs = moduleOp.getOutputLocs();
716 SmallVector<Attribute> newArgNames, newResultNames;
717 SmallVector<Type> newArgTypes, newResultTypes;
718 SmallVector<Attribute> newArgAttrs, newResultAttrs;
719 SmallVector<Location> newArgLocs, newResultLocs;
722 oldArgTypes, oldArgAttrs, oldArgLocs, newArgNames,
723 newArgTypes, newArgAttrs, newArgLocs, body);
726 oldResultTypes, oldResultAttrs, oldResultLocs,
727 newResultNames, newResultTypes, newResultAttrs,
733 moduleOp.setHWModuleType(modty);
734 moduleOp.setAllInputAttrs(newArgAttrs);
735 moduleOp.setAllOutputAttrs(newResultAttrs);
737 newArgLocs.append(newResultLocs.begin(), newResultLocs.end());
738 moduleOp.setAllPortLocs(newArgLocs);
741 void HWModuleOp::build(OpBuilder &
builder, OperationState &result,
742 StringAttr name,
const ModulePortInfo &ports,
743 ArrayAttr parameters,
744 ArrayRef<NamedAttribute> attributes, StringAttr comment,
745 bool shouldEnsureTerminator) {
746 buildModule<HWModuleOp>(
builder, result, name, ports, parameters, attributes,
750 auto *bodyRegion = result.regions[0].get();
751 Block *body =
new Block();
752 bodyRegion->push_back(body);
755 auto unknownLoc =
builder.getUnknownLoc();
756 for (
auto port : ports.getInputs()) {
757 auto loc = port.loc ? Location(port.loc) : unknownLoc;
758 auto type = port.type;
759 if (port.isInOut() && !type.isa<
InOutType>())
761 body->addArgument(type, loc);
764 if (shouldEnsureTerminator)
765 HWModuleOp::ensureTerminator(*bodyRegion,
builder, result.location);
768 void HWModuleOp::build(OpBuilder &
builder, OperationState &result,
769 StringAttr name, ArrayRef<PortInfo> ports,
770 ArrayAttr parameters,
771 ArrayRef<NamedAttribute> attributes,
772 StringAttr comment) {
773 build(
builder, result, name, ModulePortInfo(ports), parameters, attributes,
777 void HWModuleOp::build(OpBuilder &
builder, OperationState &odsState,
778 StringAttr name,
const ModulePortInfo &ports,
780 ArrayRef<NamedAttribute> attributes,
781 StringAttr comment) {
782 build(
builder, odsState, name, ports, parameters, attributes, comment,
784 auto *bodyRegion = odsState.regions[0].get();
785 OpBuilder::InsertionGuard guard(
builder);
786 auto accessor = HWModulePortAccessor(odsState.location, ports, *bodyRegion);
787 builder.setInsertionPointToEnd(&bodyRegion->front());
790 llvm::SmallVector<Value> outputOperands = accessor.getOutputOperands();
791 builder.create<hw::OutputOp>(odsState.location, outputOperands);
794 void HWModuleOp::modifyPorts(
795 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
796 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
797 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
806 if (
auto vName = getVerilogNameAttr())
809 return (*this)->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
813 if (
auto vName = getVerilogNameAttr()) {
816 return (*this)->getAttrOfType<StringAttr>(
817 ::mlir::SymbolTable::getSymbolAttrName());
820 void HWModuleExternOp::build(OpBuilder &
builder, OperationState &result,
821 StringAttr name,
const ModulePortInfo &ports,
822 StringRef verilogName, ArrayAttr parameters,
823 ArrayRef<NamedAttribute> attributes) {
824 buildModule<HWModuleExternOp>(
builder, result, name, ports, parameters,
827 if (!verilogName.empty())
828 result.addAttribute(
"verilogName",
builder.getStringAttr(verilogName));
831 void HWModuleExternOp::build(OpBuilder &
builder, OperationState &result,
832 StringAttr name, ArrayRef<PortInfo> ports,
833 StringRef verilogName, ArrayAttr parameters,
834 ArrayRef<NamedAttribute> attributes) {
835 build(
builder, result, name, ModulePortInfo(ports), verilogName, parameters,
839 void HWModuleExternOp::modifyPorts(
840 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
841 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
842 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
847 void HWModuleExternOp::appendOutputs(
848 ArrayRef<std::pair<StringAttr, Value>>
outputs) {}
850 void HWModuleGeneratedOp::build(OpBuilder &
builder, OperationState &result,
851 FlatSymbolRefAttr genKind, StringAttr name,
852 const ModulePortInfo &ports,
853 StringRef verilogName, ArrayAttr parameters,
854 ArrayRef<NamedAttribute> attributes) {
855 buildModule<HWModuleGeneratedOp>(
builder, result, name, ports, parameters,
857 result.addAttribute(
"generatorKind", genKind);
858 if (!verilogName.empty())
859 result.addAttribute(
"verilogName",
builder.getStringAttr(verilogName));
862 void HWModuleGeneratedOp::build(OpBuilder &
builder, OperationState &result,
863 FlatSymbolRefAttr genKind, StringAttr name,
864 ArrayRef<PortInfo> ports, StringRef verilogName,
865 ArrayAttr parameters,
866 ArrayRef<NamedAttribute> attributes) {
867 build(
builder, result, genKind, name, ModulePortInfo(ports), verilogName,
868 parameters, attributes);
871 void HWModuleGeneratedOp::modifyPorts(
872 ArrayRef<std::pair<unsigned, PortInfo>> insertInputs,
873 ArrayRef<std::pair<unsigned, PortInfo>> insertOutputs,
874 ArrayRef<unsigned> eraseInputs, ArrayRef<unsigned> eraseOutputs) {
879 void HWModuleGeneratedOp::appendOutputs(
880 ArrayRef<std::pair<StringAttr, Value>>
outputs) {}
884 if (
auto symRef = attrs.get(
"hw.exportPort"))
885 return symRef.cast<InnerSymAttr>();
889 static bool hasAttribute(StringRef name, ArrayRef<NamedAttribute> attrs) {
890 for (
auto &argAttr : attrs)
891 if (argAttr.getName() == name)
896 static Attribute
getAttribute(StringRef name, ArrayRef<NamedAttribute> attrs) {
897 for (
auto &argAttr : attrs)
898 if (argAttr.getName() == name)
899 return argAttr.getValue();
904 ArrayRef<DictionaryAttr> argAttrs,
905 ArrayRef<DictionaryAttr> resultAttrs) {
911 llvm::concat<const Attribute>(argAttrs, resultAttrs))));
915 ArrayRef<OpAsmParser::Argument> args,
916 ArrayRef<DictionaryAttr> resultAttrs) {
917 SmallVector<DictionaryAttr> argAttrs;
918 for (
const auto &arg : args)
919 argAttrs.push_back(arg.attrs);
923 template <
typename ModuleTy>
927 using namespace mlir::function_interface_impl;
928 auto loc = parser.getCurrentLocation();
931 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
935 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
940 FlatSymbolRefAttr kindAttr;
942 if (parser.parseComma() ||
943 parser.parseAttribute(kindAttr,
"generatorKind", result.attributes)) {
949 ArrayAttr parameters;
954 bool isVariadic =
false;
955 SmallVector<OpAsmParser::Argument, 4> entryArgs;
956 SmallVector<Attribute> argNames;
957 SmallVector<Attribute> argLocs;
958 SmallVector<Attribute> resultNames;
959 SmallVector<DictionaryAttr> resultAttrs;
960 SmallVector<Attribute> resultLocs;
961 TypeAttr functionType;
963 parser, isVariadic, entryArgs, argNames, argLocs, resultNames,
964 resultAttrs, resultLocs, functionType)))
968 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
974 loc,
"explicit `resultNames` / `parameters` attributes not allowed");
978 SmallVector<Attribute> portLocs;
979 portLocs.append(argLocs.begin(), argLocs.end());
980 portLocs.append(resultLocs.begin(), resultLocs.end());
982 auto *context = result.getContext();
984 auto attr =
getAttribute(
"argNames", result.attributes);
986 cast<FunctionType>(functionType.getValue()),
987 attr ? cast<ArrayAttr>(attr).getValue() : argNames, resultNames);
988 result.attributes.erase(
"argNames");
989 result.addAttribute(
"portLocs",
ArrayAttr::get(context, portLocs));
990 result.addAttribute(
"parameters", parameters);
993 result.addAttribute(ModuleTy::getModuleTypeAttrName(result.name),
1000 auto *body = result.addRegion();
1002 if (parser.parseRegion(*body, entryArgs))
1005 HWModuleOp::ensureTerminator(*body, parser.getBuilder(), result.location);
1010 ParseResult HWModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1011 return parseHWModuleOp<HWModuleOp>(parser, result);
1014 ParseResult HWModuleExternOp::parse(OpAsmParser &parser,
1015 OperationState &result) {
1016 return parseHWModuleOp<HWModuleExternOp>(parser, result,
ExternMod);
1019 ParseResult HWModuleGeneratedOp::parse(OpAsmParser &parser,
1020 OperationState &result) {
1021 return parseHWModuleOp<HWModuleGeneratedOp>(parser, result,
GenMod);
1025 if (
auto mod = dyn_cast<HWModuleLike>(op))
1026 return mod.getHWModuleType().getFuncType();
1027 return cast<mlir::FunctionOpInterface>(op)
1029 .cast<FunctionType>();
1032 template <
typename ModuleTy>
1034 using namespace mlir::function_interface_impl;
1036 FunctionType fnType = mod.getHWModuleType().getFuncType();
1037 auto argTypes = fnType.getInputs();
1038 auto resultTypes = fnType.getResults();
1043 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1044 if (
auto visibility = mod.getOperation()->template getAttrOfType<StringAttr>(
1045 visibilityAttrName))
1046 p << visibility.getValue() <<
' ';
1049 p.printSymbolName(SymbolTable::getSymbolName(mod.getOperation()).getValue());
1050 if (
auto gen = dyn_cast<HWModuleGeneratedOp>(mod.getOperation())) {
1052 p.printSymbolName(gen.getGeneratorKind());
1057 p, mod.getOperation(),
1058 mod.getOperation()->template getAttrOfType<ArrayAttr>(
"parameters"));
1060 bool needArgNamesAttr =
false;
1065 SmallVector<StringRef, 3> omittedAttrs;
1066 if (isa<HWModuleGeneratedOp>(mod.getOperation()))
1067 omittedAttrs.push_back(
"generatorKind");
1068 if (!needArgNamesAttr)
1069 omittedAttrs.push_back(
"argNames");
1070 omittedAttrs.push_back(
"portLocs");
1071 omittedAttrs.push_back(
1072 ModuleTy::getModuleTypeAttrName(mod.getOperation()->getName()));
1073 omittedAttrs.push_back(
"per_port_attrs");
1074 omittedAttrs.push_back(
"resultNames");
1075 omittedAttrs.push_back(
"parameters");
1076 omittedAttrs.push_back(visibilityAttrName);
1077 omittedAttrs.push_back(SymbolTable::getSymbolAttrName());
1078 if (mod.getOperation()
1079 ->template getAttrOfType<StringAttr>(
"comment")
1082 omittedAttrs.push_back(
"comment");
1084 auto attrs = mod->getAttrs();
1085 SmallVector<NamedAttribute> realAttrs(attrs.begin(), attrs.end());
1086 realAttrs.push_back(
1089 p.printOptionalAttrDictWithKeyword(realAttrs, omittedAttrs);
1092 void HWModuleExternOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1093 void HWModuleGeneratedOp::print(OpAsmPrinter &p) {
printModuleOp(p, *
this); }
1095 void HWModuleOp::print(OpAsmPrinter &p) {
1099 Region &body = getBody();
1100 if (!body.empty()) {
1102 p.printRegion(body,
false,
1108 assert(isa<HWModuleLike>(module) &&
1109 "verifier hook should only be called on modules");
1111 auto moduleType = module.getHWModuleType();
1113 auto argLocs = module.getInputLocs();
1114 if (argLocs.size() != moduleType.getNumInputs())
1115 return module->emitOpError(
"incorrect number of argument locations");
1117 auto resultLocs = module.getOutputLocs();
1118 if (resultLocs.size() != moduleType.getNumOutputs())
1119 return module->emitOpError(
"incorrect number of result locations");
1121 SmallPtrSet<Attribute, 4> paramNames;
1124 for (
auto param : module->getAttrOfType<ArrayAttr>(
"parameters")) {
1125 auto paramAttr = param.cast<ParamDeclAttr>();
1129 if (!paramNames.insert(paramAttr.getName()).second)
1130 return module->emitOpError(
"parameter ")
1131 << paramAttr <<
" has the same name as a previous parameter";
1134 auto value = paramAttr.getValue();
1138 auto typedValue = value.dyn_cast<TypedAttr>();
1140 return module->emitOpError(
"parameter ")
1141 << paramAttr <<
" should have a typed value; has value " << value;
1143 if (typedValue.getType() != paramAttr.getType())
1144 return module->emitOpError(
"parameter ")
1145 << paramAttr <<
" should have type " << paramAttr.getType()
1146 <<
"; has type " << typedValue.getType();
1158 LogicalResult HWModuleOp::verify() {
1163 auto *body = getBodyBlock();
1166 auto numInputs = type.getNumInputs();
1167 if (body->getNumArguments() != numInputs)
1168 return emitOpError(
"entry block must have")
1169 << numInputs <<
" arguments to match module signature";
1172 for (
auto [arg, type, loc] : llvm::zip(getBodyBlock()->getArguments(),
1173 getInputTypes(), getInputLocs())) {
1174 if (arg.getType() != type)
1175 return emitOpError(
"block argument types should match signature types");
1176 if (arg.getLoc() != loc.cast<LocationAttr>())
1178 "block argument locations should match signature locations");
1186 std::pair<StringAttr, BlockArgument>
1187 HWModuleOp::insertInput(
unsigned index, StringAttr name, Type ty) {
1191 for (
auto port : ports)
1192 ns.
newName(port.name.getValue());
1195 Block *body = getBodyBlock();
1199 port.name = nameAttr;
1206 return {nameAttr, body->getArgument(index)};
1209 void HWModuleOp::insertOutputs(
unsigned index,
1210 ArrayRef<std::pair<StringAttr, Value>>
outputs) {
1212 auto output = cast<OutputOp>(getBodyBlock()->getTerminator());
1213 assert(index <= output->getNumOperands() &&
"invalid output index");
1216 SmallVector<std::pair<unsigned, PortInfo>> indexedNewPorts;
1217 for (
auto &[name, value] :
outputs) {
1221 port.type = value.getType();
1222 indexedNewPorts.emplace_back(index, port);
1228 for (
auto &[name, value] :
outputs)
1229 output->insertOperands(index++, value);
1232 void HWModuleOp::appendOutputs(ArrayRef<std::pair<StringAttr, Value>>
outputs) {
1233 return insertOutputs(getNumOutputPorts(),
outputs);
1236 void HWModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1241 void HWModuleExternOp::getAsmBlockArgumentNames(
1246 template <
typename ModTy>
1248 SmallVector<Location> retval;
1249 auto locs = module.getPortLocs();
1251 retval.push_back(cast<Location>(l));
1252 assert(!locs.size() || locs.size() == module.getNumPorts());
1268 template <
typename ModTy>
1270 std::vector<Attribute> nLocs(locs.begin(), locs.end());
1271 module.setPortLocsAttr(
ArrayAttr::get(module.getContext(), nLocs));
1286 template <
typename ModTy>
1288 auto numInputs = module.getNumInputPorts();
1289 SmallVector<Attribute> argNames(names.begin(), names.begin() + numInputs);
1290 SmallVector<Attribute> resNames(names.begin() + numInputs, names.end());
1291 auto oldType = module.getModuleType();
1292 SmallVector<ModulePort> newPorts(oldType.getPorts().begin(),
1293 oldType.getPorts().end());
1294 for (
size_t i = 0UL, e = newPorts.size(); i != e; ++i)
1295 newPorts[i].name = cast<StringAttr>(names[i]);
1297 module.setModuleType(newType);
1312 SmallVector<Attribute> HWModuleOp::getAllPortAttrs() {
1313 auto attrs = getPerPortAttrs();
1314 if (attrs && !attrs.empty())
1315 return {attrs.getValue().begin(), attrs.getValue().end()};
1319 SmallVector<Attribute> HWModuleExternOp::getAllPortAttrs() {
1320 auto attrs = getPerPortAttrs();
1321 if (attrs && !attrs.empty())
1322 return {attrs.getValue().begin(), attrs.getValue().end()};
1326 SmallVector<Attribute> HWModuleGeneratedOp::getAllPortAttrs() {
1327 auto attrs = getPerPortAttrs();
1328 if (attrs && !attrs.empty())
1329 return {attrs.getValue().begin(), attrs.getValue().end()};
1333 void HWModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1334 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1337 void HWModuleExternOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1338 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1341 void HWModuleGeneratedOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
1342 setPerPortAttrsAttr(
arrayOrEmpty(getContext(), attrs));
1345 void HWModuleOp::removeAllPortAttrs() {
1349 void HWModuleExternOp::removeAllPortAttrs() {
1353 void HWModuleGeneratedOp::removeAllPortAttrs() {
1359 template <
typename ModTy>
1361 auto argAttrs = mod.getAllInputAttrs();
1362 auto resAttrs = mod.getAllOutputAttrs();
1364 unsigned newNumArgs = type.getNumInputs();
1365 unsigned newNumResults = type.getNumOutputs();
1368 argAttrs.resize(newNumArgs, emptyDict);
1369 resAttrs.resize(newNumResults, emptyDict);
1371 SmallVector<Attribute> attrs;
1372 attrs.append(argAttrs.begin(), argAttrs.end());
1373 attrs.append(resAttrs.begin(), resAttrs.end());
1376 return mod.removeAllPortAttrs();
1377 mod.setAllPortAttrs(attrs);
1394 Operation *HWModuleGeneratedOp::getGeneratorKindOp() {
1395 auto topLevelModuleOp = (*this)->getParentOfType<ModuleOp>();
1396 return topLevelModuleOp.lookupSymbol(getGeneratorKind());
1400 HWModuleGeneratedOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1401 auto *referencedKind =
1402 symbolTable.lookupNearestSymbolFrom(*
this, getGeneratorKindAttr());
1404 if (referencedKind ==
nullptr)
1405 return emitError(
"Cannot find generator definition '")
1406 << getGeneratorKind() <<
"'";
1408 if (!isa<HWGeneratorSchemaOp>(referencedKind))
1409 return emitError(
"Symbol resolved to '")
1410 << referencedKind->getName()
1411 <<
"' which is not a HWGeneratorSchemaOp";
1413 auto referencedKindOp = dyn_cast<HWGeneratorSchemaOp>(referencedKind);
1414 auto paramRef = referencedKindOp.getRequiredAttrs();
1415 auto dict = (*this)->getAttrDictionary();
1416 for (
auto str : paramRef) {
1417 auto strAttr = str.dyn_cast<StringAttr>();
1419 return emitError(
"Unknown attribute type, expected a string");
1420 if (!dict.get(strAttr.getValue()))
1421 return emitError(
"Missing attribute '") << strAttr.getValue() <<
"'";
1427 LogicalResult HWModuleGeneratedOp::verify() {
1431 void HWModuleGeneratedOp::getAsmBlockArgumentNames(
1436 LogicalResult HWModuleOp::verifyBody() {
return success(); }
1438 template <
typename ModuleTy>
1440 auto modTy = mod.getHWModuleType();
1442 SmallVector<PortInfo> retval;
1443 for (
unsigned i = 0, e = modTy.getNumPorts(); i < e; ++i) {
1444 LocationAttr loc = mod.getPortLoc(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),
1454 return ModulePortInfo(retval);
1462 void InstanceOp::build(OpBuilder &
builder, OperationState &result,
1463 Operation *module, StringAttr name,
1464 ArrayRef<Value>
inputs, ArrayAttr parameters,
1465 InnerSymAttr innerSym) {
1467 parameters =
builder.getArrayAttr({});
1469 auto mod = cast<hw::HWModuleLike>(module);
1470 auto argNames =
builder.getArrayAttr(mod.getInputNames());
1471 auto resultNames =
builder.getArrayAttr(mod.getOutputNames());
1472 FunctionType modType = mod.getHWModuleType().getFuncType();
1473 build(
builder, result, modType.getResults(), name,
1475 argNames, resultNames, parameters, innerSym);
1478 std::optional<size_t> InstanceOp::getTargetResultIndex() {
1480 return std::nullopt;
1483 Operation *InstanceOp::getReferencedModuleSlow() {
1484 return getReferencedModuleCached(
nullptr);
1487 LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1489 *
this, getModuleNameAttr(), getInputs(), getResultTypes(), getArgNames(),
1490 getResultNames(), getParameters(), symbolTable);
1493 LogicalResult InstanceOp::verify() {
1494 auto module = (*this)->getParentOfType<HWModuleOp>();
1498 auto moduleParameters = module->getAttrOfType<ArrayAttr>(
"parameters");
1500 [&](
const std::function<bool(InFlightDiagnostic &)> &fn) {
1501 auto diag = emitOpError();
1503 diag.attachNote(module->getLoc()) <<
"module declared here";
1506 getParameters(), moduleParameters, emitError);
1509 ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
1510 StringAttr instanceNameAttr;
1511 InnerSymAttr innerSym;
1512 FlatSymbolRefAttr moduleNameAttr;
1513 SmallVector<OpAsmParser::UnresolvedOperand, 4> inputsOperands;
1514 SmallVector<Type, 1> inputsTypes, allResultTypes;
1515 ArrayAttr argNames, resultNames, parameters;
1516 auto noneType = parser.getBuilder().getType<NoneType>();
1518 if (parser.parseAttribute(instanceNameAttr, noneType,
"instanceName",
1522 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1525 if (parser.parseCustomAttributeWithFallback(innerSym))
1530 llvm::SMLoc parametersLoc, inputsOperandsLoc;
1531 if (parser.parseAttribute(moduleNameAttr, noneType,
"moduleName",
1532 result.attributes) ||
1533 parser.getCurrentLocation(¶metersLoc) ||
1536 parser.resolveOperands(inputsOperands, inputsTypes, inputsOperandsLoc,
1538 parser.parseArrow() ||
1540 parser.parseOptionalAttrDict(result.attributes)) {
1544 result.addAttribute(
"argNames", argNames);
1545 result.addAttribute(
"resultNames", resultNames);
1546 result.addAttribute(
"parameters", parameters);
1547 result.addTypes(allResultTypes);
1551 void InstanceOp::print(OpAsmPrinter &p) {
1553 p.printAttributeWithoutType(getInstanceNameAttr());
1554 if (
auto attr = getInnerSymAttr()) {
1559 p.printAttributeWithoutType(getModuleNameAttr());
1566 p.printOptionalAttrDict(
1567 (*this)->getAttrs(),
1569 InnerSymbolTable::getInnerSymbolAttrName(),
"moduleName",
1570 "argNames",
"resultNames",
"parameters"});
1575 StringAttr InstanceOp::getArgumentName(
size_t idx) {
1581 StringAttr InstanceOp::getResultName(
size_t idx) {
1586 void InstanceOp::setArgumentName(
size_t i, StringAttr name) {
1591 void InstanceOp::setResultName(
size_t i, StringAttr name) {
1599 getResultNames(), getResults());
1605 auto argNames = (*this)->getAttrOfType<ArrayAttr>(
"argNames");
1607 auto argLocs = (*this)->getAttrOfType<ArrayAttr>(
"argLocs");
1608 for (
unsigned i = 0, e = argTypes.size(); i < e; ++i) {
1609 auto type = argTypes[i];
1612 if (
auto inout = type.dyn_cast<
InOutType>()) {
1613 type = inout.getElementType();
1619 loc = argLocs[i].cast<LocationAttr>();
1620 inputs.push_back({{argNames[i].cast<StringAttr>(), type, direction},
1627 auto resultNames = (*this)->getAttrOfType<ArrayAttr>(
"resultNames");
1629 auto resultLocs = (*this)->getAttrOfType<ArrayAttr>(
"resultLocs");
1630 for (
unsigned i = 0, e = resultTypes.size(); i < e; ++i) {
1633 loc = resultLocs[i].cast<LocationAttr>();
1634 outputs.push_back({{resultNames[i].cast<StringAttr>(), resultTypes[i],
1645 return getNumInputPorts() + getNumOutputPorts();
1648 size_t InstanceOp::getNumInputPorts() {
return getNumOperands(); }
1650 size_t InstanceOp::getNumOutputPorts() {
return getNumResults(); }
1652 size_t InstanceOp::getPortIdForInputId(
size_t idx) {
return idx; }
1654 size_t InstanceOp::getPortIdForOutputId(
size_t idx) {
1655 return idx + getNumInputPorts();
1658 void InstanceOp::getValues(SmallVectorImpl<Value> &values,
1659 const ModulePortInfo &mpi) {
1660 size_t inputPort = 0, resultPort = 0;
1661 values.resize(mpi.size());
1662 auto results = getResults();
1663 auto inputs = getInputs();
1664 for (
auto [idx, port] : llvm::enumerate(mpi))
1665 if (mpi.at(idx).isOutput())
1666 values[idx] = results[resultPort++];
1668 values[idx] =
inputs[inputPort++];
1676 LogicalResult OutputOp::verify() {
1680 if (
auto mod = dyn_cast<HWModuleOp>((*this)->getParentOp()))
1681 modType = mod.getHWModuleType();
1682 else if (
auto mod = dyn_cast<HWTestModuleOp>((*this)->getParentOp()))
1683 modType = mod.getModuleType();
1685 emitOpError(
"must have a module parent");
1688 auto modResults = modType.getOutputTypes();
1689 OperandRange outputValues = getOperands();
1690 if (modResults.size() != outputValues.size()) {
1691 emitOpError(
"must have same number of operands as region results.");
1696 for (
size_t i = 0, e = modResults.size(); i < e; ++i) {
1697 if (modResults[i] != outputValues[i].getType()) {
1698 emitOpError(
"output types must match module. In "
1700 << i <<
", expected " << modResults[i] <<
", but got "
1701 << outputValues[i].getType() <<
".";
1716 if (p.parseType(type))
1717 return p.emitError(p.getCurrentLocation(),
"Expected type");
1718 auto arrType = type_dyn_cast<ArrayType>(type);
1720 return p.emitError(p.getCurrentLocation(),
"Expected !hw.array type");
1722 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1729 p.printType(srcType);
1732 ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
1733 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
1734 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
1737 if (parser.parseOperandList(operands) ||
1738 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
1739 parser.parseType(elemType))
1742 if (operands.size() == 0)
1743 return parser.emitError(inputOperandsLoc,
1744 "Cannot construct an array of length 0");
1747 for (
auto operand : operands)
1748 if (parser.resolveOperand(operand, elemType, result.operands))
1753 void ArrayCreateOp::print(OpAsmPrinter &p) {
1755 p.printOperands(getInputs());
1756 p.printOptionalAttrDict((*this)->getAttrs());
1757 p <<
" : " << getInputs()[0].getType();
1760 void ArrayCreateOp::build(OpBuilder &b, OperationState &state,
1761 ValueRange values) {
1762 assert(values.size() > 0 &&
"Cannot build array of zero elements");
1763 Type elemType = values[0].getType();
1766 [elemType](Value v) ->
bool {
return v.getType() == elemType; }) &&
1767 "All values must have same type.");
1768 build(b, state,
ArrayType::get(elemType, values.size()), values);
1771 LogicalResult ArrayCreateOp::verify() {
1772 unsigned returnSize = getType().cast<ArrayType>().getNumElements();
1773 if (getInputs().
size() != returnSize)
1778 OpFoldResult ArrayCreateOp::fold(FoldAdaptor adaptor) {
1779 if (llvm::any_of(adaptor.getInputs(), [](Attribute attr) { return !attr; }))
1786 if (
auto constBase = base.getDefiningOp<hw::ConstantOp>()) {
1787 if (
auto constIndex = index.getDefiningOp<hw::ConstantOp>()) {
1791 auto baseValue = constBase.getValue();
1792 auto indexValue = constIndex.getValue();
1794 unsigned bits = baseValue.getBitWidth();
1795 assert(
bits == indexValue.getBitWidth() &&
"mismatched widths");
1797 if (bits < 64 && offset >= (1ull <<
bits))
1800 APInt baseExt = baseValue.zextOrTrunc(
bits + 1);
1801 APInt indexExt = indexValue.zextOrTrunc(
bits + 1);
1802 return baseExt + offset == indexExt;
1810 PatternRewriter &rewriter) {
1812 auto arrayTy = hw::type_cast<ArrayType>(op.getType());
1813 if (arrayTy.getNumElements() <= 1)
1815 auto elemTy = arrayTy.getElementType();
1824 SmallVector<Chunk> chunks;
1825 for (Value value : llvm::reverse(op.getInputs())) {
1826 auto get = value.getDefiningOp<ArrayGetOp>();
1830 Value input =
get.getInput();
1831 Value index =
get.getIndex();
1832 if (!chunks.empty()) {
1833 auto &c = *chunks.rbegin();
1834 if (c.input ==
get.getInput() &&
isOffset(c.index, index, c.size)) {
1840 chunks.push_back(Chunk{input, index, 1});
1844 if (chunks.size() == 1) {
1845 auto &chunk = chunks[0];
1846 rewriter.replaceOp(op, rewriter.createOrFold<ArraySliceOp>(
1847 op.getLoc(), arrayTy, chunk.input, chunk.index));
1853 if (chunks.size() * 2 < arrayTy.getNumElements()) {
1854 SmallVector<Value> slices;
1855 for (
auto &chunk : llvm::reverse(chunks)) {
1857 slices.push_back(rewriter.createOrFold<ArraySliceOp>(
1858 op.getLoc(), sliceTy, chunk.input, chunk.index));
1860 rewriter.replaceOpWithNewOp<ArrayConcatOp>(op, arrayTy, slices);
1867 LogicalResult ArrayCreateOp::canonicalize(ArrayCreateOp op,
1868 PatternRewriter &rewriter) {
1874 Value ArrayCreateOp::getUniformElement() {
1875 if (!getInputs().
empty() && llvm::all_equal(getInputs()))
1876 return getInputs()[0];
1881 auto idxOp = dyn_cast_or_null<ConstantOp>(value.getDefiningOp());
1883 return std::nullopt;
1884 APInt idxAttr = idxOp.getValue();
1885 if (idxAttr.getBitWidth() > 64)
1886 return std::nullopt;
1887 return idxAttr.getLimitedValue();
1890 LogicalResult ArraySliceOp::verify() {
1891 unsigned inputSize =
1892 type_cast<ArrayType>(getInput().getType()).getNumElements();
1893 if (llvm::Log2_64_Ceil(inputSize) !=
1894 getLowIndex().getType().getIntOrFloatBitWidth())
1896 "ArraySlice: index width must match clog2 of array size");
1900 OpFoldResult ArraySliceOp::fold(FoldAdaptor adaptor) {
1902 if (getType() == getInput().getType())
1907 LogicalResult ArraySliceOp::canonicalize(ArraySliceOp op,
1908 PatternRewriter &rewriter) {
1909 auto sliceTy = hw::type_cast<ArrayType>(op.getType());
1910 auto elemTy = sliceTy.getElementType();
1911 uint64_t sliceSize = sliceTy.getNumElements();
1915 if (sliceSize == 1) {
1917 auto get = rewriter.create<ArrayGetOp>(op.getLoc(), op.getInput(),
1919 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(),
1928 auto inputOp = op.getInput().getDefiningOp();
1929 if (
auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
1931 if (inputSlice == op)
1934 auto inputIndex = inputSlice.getLowIndex();
1936 if (!inputOffsetOpt)
1939 uint64_t offset = *offsetOpt + *inputOffsetOpt;
1941 rewriter.create<ConstantOp>(op.getLoc(), inputIndex.getType(), offset);
1942 rewriter.replaceOpWithNewOp<ArraySliceOp>(op, op.getType(),
1943 inputSlice.getInput(), lowIndex);
1947 if (
auto inputCreate = dyn_cast_or_null<ArrayCreateOp>(inputOp)) {
1949 auto inputs = inputCreate.getInputs();
1951 uint64_t begin =
inputs.size() - *offsetOpt - sliceSize;
1952 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(),
1953 inputs.slice(begin, sliceSize));
1957 if (
auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
1959 SmallVector<Value> chunks;
1960 uint64_t sliceStart = *offsetOpt;
1961 for (
auto input : llvm::reverse(inputConcat.getInputs())) {
1963 uint64_t inputSize =
1964 hw::type_cast<ArrayType>(input.getType()).getNumElements();
1965 if (inputSize == 0 || inputSize <= sliceStart) {
1966 sliceStart -= inputSize;
1971 uint64_t cutEnd = std::min(inputSize, sliceStart + sliceSize);
1972 uint64_t cutSize = cutEnd - sliceStart;
1973 assert(cutSize != 0 &&
"slice cannot be empty");
1975 if (cutSize == inputSize) {
1977 assert(sliceStart == 0 &&
"invalid cut size");
1978 chunks.push_back(input);
1981 unsigned width = inputSize == 1 ? 1 : llvm::Log2_64_Ceil(inputSize);
1982 auto lowIndex = rewriter.create<ConstantOp>(
1983 op.getLoc(), rewriter.getIntegerType(
width), sliceStart);
1984 chunks.push_back(rewriter.create<ArraySliceOp>(
1989 sliceSize -= cutSize;
1994 assert(chunks.size() > 0 &&
"missing sliced items");
1995 if (chunks.size() == 1)
1996 rewriter.replaceOp(op, chunks[0]);
1998 rewriter.replaceOpWithNewOp<ArrayConcatOp>(
1999 op, llvm::to_vector(llvm::reverse(chunks)));
2010 SmallVectorImpl<Type> &inputTypes,
2013 uint64_t resultSize = 0;
2015 auto parseElement = [&]() -> ParseResult {
2017 if (p.parseType(ty))
2019 auto arrTy = type_dyn_cast<ArrayType>(ty);
2021 return p.emitError(p.getCurrentLocation(),
"Expected !hw.array type");
2022 if (elemType && elemType != arrTy.getElementType())
2023 return p.emitError(p.getCurrentLocation(),
"Expected array element type ")
2026 elemType = arrTy.getElementType();
2027 inputTypes.push_back(ty);
2028 resultSize += arrTy.getNumElements();
2032 if (p.parseCommaSeparatedList(parseElement))
2040 TypeRange inputTypes, Type resultType) {
2041 llvm::interleaveComma(inputTypes, p, [&p](Type t) { p << t; });
2044 void ArrayConcatOp::build(OpBuilder &b, OperationState &state,
2045 ValueRange values) {
2046 assert(!values.empty() &&
"Cannot build array of zero elements");
2047 ArrayType arrayTy = values[0].getType().cast<ArrayType>();
2048 Type elemTy = arrayTy.getElementType();
2049 assert(llvm::all_of(values,
2050 [elemTy](Value v) ->
bool {
2051 return v.getType().isa<ArrayType>() &&
2052 v.getType().cast<ArrayType>().getElementType() ==
2055 "All values must be of ArrayType with the same element type.");
2057 uint64_t resultSize = 0;
2058 for (Value val : values)
2059 resultSize += val.getType().cast<ArrayType>().getNumElements();
2063 OpFoldResult ArrayConcatOp::fold(FoldAdaptor adaptor) {
2064 auto inputs = adaptor.getInputs();
2065 SmallVector<Attribute> array;
2066 for (
size_t i = 0, e = getNumOperands(); i < e; ++i) {
2069 llvm::copy(
inputs[i].cast<ArrayAttr>(), std::back_inserter(array));
2076 for (
auto input : op.getInputs())
2077 if (!input.getDefiningOp<ArrayCreateOp>())
2080 SmallVector<Value> items;
2081 for (
auto input : op.getInputs()) {
2082 auto create = cast<ArrayCreateOp>(input.getDefiningOp());
2083 for (
auto item : create.getInputs())
2084 items.push_back(item);
2087 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, items);
2098 SmallVector<Location> locs;
2101 SmallVector<Value> items;
2102 std::optional<Slice> last;
2103 bool changed =
false;
2105 auto concatenate = [&] {
2110 items.push_back(last->op);
2119 auto origTy = hw::type_cast<ArrayType>(last->input.getType());
2120 auto arrayTy =
ArrayType::get(origTy.getElementType(), last->size);
2121 items.push_back(rewriter.createOrFold<ArraySliceOp>(
2122 loc, arrayTy, last->input, last->index));
2127 auto append = [&](Value op, Value input, Value index,
size_t size) {
2132 if (last->input == input &&
isOffset(last->index, index, last->size)) {
2135 last->locs.push_back(op.getLoc());
2140 last.emplace(Slice{input, index,
size, op, {op.getLoc()}});
2143 for (
auto item : llvm::reverse(op.getInputs())) {
2144 if (
auto slice = item.getDefiningOp<ArraySliceOp>()) {
2145 auto size = hw::type_cast<ArrayType>(slice.getType()).getNumElements();
2146 append(item, slice.getInput(), slice.getLowIndex(),
size);
2150 if (
auto create = item.getDefiningOp<ArrayCreateOp>()) {
2151 if (create.getInputs().size() == 1) {
2152 if (
auto get = create.getInputs()[0].getDefiningOp<ArrayGetOp>()) {
2160 items.push_back(item);
2167 if (items.size() == 1) {
2168 rewriter.replaceOp(op, items[0]);
2170 std::reverse(items.begin(), items.end());
2171 rewriter.replaceOpWithNewOp<ArrayConcatOp>(op, items);
2176 LogicalResult ArrayConcatOp::canonicalize(ArrayConcatOp op,
2177 PatternRewriter &rewriter) {
2193 ParseResult EnumConstantOp::parse(OpAsmParser &parser, OperationState &result) {
2200 auto loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());
2201 if (parser.parseKeyword(&field) || parser.parseColonType(type))
2210 result.addAttribute(
"field", fieldAttr);
2211 result.addTypes(type);
2216 void EnumConstantOp::print(OpAsmPrinter &p) {
2217 p <<
" " << getField().getField().getValue() <<
" : "
2218 << getField().getType().getValue();
2222 function_ref<
void(Value, StringRef)> setNameFn) {
2223 setNameFn(getResult(), getField().getField().str());
2226 void EnumConstantOp::build(OpBuilder &
builder, OperationState &odsState,
2227 EnumFieldAttr field) {
2228 return build(
builder, odsState, field.getType().getValue(), field);
2231 OpFoldResult EnumConstantOp::fold(FoldAdaptor adaptor) {
2232 assert(adaptor.getOperands().empty() &&
"constant has no operands");
2233 return getFieldAttr();
2236 LogicalResult EnumConstantOp::verify() {
2237 auto fieldAttr = getFieldAttr();
2238 auto fieldType = fieldAttr.getType().getValue();
2241 if (fieldType != getType())
2242 emitOpError(
"return type ")
2243 << getType() <<
" does not match attribute type " << fieldAttr;
2251 LogicalResult EnumCmpOp::verify() {
2253 auto lhsType = type_cast<EnumType>(getLhs().getType());
2254 auto rhsType = type_cast<EnumType>(getRhs().getType());
2255 if (rhsType != lhsType)
2256 emitOpError(
"types do not match");
2264 ParseResult StructCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2265 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2266 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
2267 Type declOrAliasType;
2269 if (parser.parseLParen() || parser.parseOperandList(operands) ||
2270 parser.parseRParen() || parser.parseOptionalAttrDict(result.attributes) ||
2271 parser.parseColonType(declOrAliasType))
2274 auto declType = type_dyn_cast<StructType>(declOrAliasType);
2276 return parser.emitError(parser.getNameLoc(),
2277 "expected !hw.struct type or alias");
2279 llvm::SmallVector<Type, 4> structInnerTypes;
2280 declType.getInnerTypes(structInnerTypes);
2281 result.addTypes(declOrAliasType);
2283 if (parser.resolveOperands(operands, structInnerTypes, inputOperandsLoc,
2289 void StructCreateOp::print(OpAsmPrinter &printer) {
2291 printer.printOperands(getInput());
2293 printer.printOptionalAttrDict((*this)->getAttrs());
2294 printer <<
" : " << getType();
2297 LogicalResult StructCreateOp::verify() {
2298 auto elements = hw::type_cast<StructType>(getType()).getElements();
2300 if (elements.size() != getInput().
size())
2301 return emitOpError(
"structure field count mismatch");
2303 for (
const auto &[field, value] : llvm::zip(elements, getInput()))
2304 if (field.type != value.getType())
2305 return emitOpError(
"structure field `")
2306 << field.name <<
"` type does not match";
2311 OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
2313 if (!getInput().
empty())
2314 if (
auto explodeOp = getInput()[0].getDefiningOp<StructExplodeOp>();
2315 explodeOp && getInput() == explodeOp.getResults() &&
2316 getResult().getType() == explodeOp.getInput().getType())
2317 return explodeOp.getInput();
2319 auto inputs = adaptor.getInput();
2320 if (llvm::any_of(
inputs, [](Attribute attr) {
return !attr; }))
2329 ParseResult StructExplodeOp::parse(OpAsmParser &parser,
2330 OperationState &result) {
2331 OpAsmParser::UnresolvedOperand operand;
2334 if (parser.parseOperand(operand) ||
2335 parser.parseOptionalAttrDict(result.attributes) ||
2336 parser.parseColonType(declType))
2338 auto structType = type_dyn_cast<StructType>(declType);
2340 return parser.emitError(parser.getNameLoc(),
2341 "invalid kind of type specified");
2343 llvm::SmallVector<Type, 4> structInnerTypes;
2344 structType.getInnerTypes(structInnerTypes);
2345 result.addTypes(structInnerTypes);
2347 if (parser.resolveOperand(operand, declType, result.operands))
2352 void StructExplodeOp::print(OpAsmPrinter &printer) {
2354 printer.printOperand(getInput());
2355 printer.printOptionalAttrDict((*this)->getAttrs());
2356 printer <<
" : " << getInput().getType();
2359 LogicalResult StructExplodeOp::fold(FoldAdaptor adaptor,
2360 SmallVectorImpl<OpFoldResult> &results) {
2361 auto input = adaptor.getInput();
2364 llvm::copy(input.cast<ArrayAttr>(), std::back_inserter(results));
2368 LogicalResult StructExplodeOp::canonicalize(StructExplodeOp op,
2369 PatternRewriter &rewriter) {
2370 auto *inputOp = op.getInput().getDefiningOp();
2371 auto elements = type_cast<StructType>(op.getInput().getType()).getElements();
2372 auto result = failure();
2373 for (
auto [element, res] : llvm::zip(elements, op.getResults())) {
2375 rewriter.replaceAllUsesWith(res, foldResult);
2383 function_ref<
void(Value, StringRef)> setNameFn) {
2384 auto structType = type_cast<StructType>(getInput().getType());
2385 for (
auto [res, field] : llvm::zip(getResults(), structType.getElements()))
2386 setNameFn(res, field.name.str());
2389 void StructExplodeOp::build(OpBuilder &odsBuilder, OperationState &odsState,
2391 StructType inputType = input.getType().dyn_cast<StructType>();
2393 SmallVector<Type, 16> fieldTypes;
2394 for (
auto field : inputType.getElements())
2395 fieldTypes.push_back(field.type);
2396 build(odsBuilder, odsState, fieldTypes, input);
2405 template <
typename AggregateType>
2407 OpAsmParser::UnresolvedOperand operand;
2408 StringAttr fieldName;
2411 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2412 parser.parseAttribute(fieldName,
"field", result.attributes) ||
2413 parser.parseRSquare() ||
2414 parser.parseOptionalAttrDict(result.attributes) ||
2415 parser.parseColonType(declType))
2417 auto aggType = type_dyn_cast<AggregateType>(declType);
2419 return parser.emitError(parser.getNameLoc(),
2420 "invalid kind of type specified");
2422 Type resultType = aggType.getFieldType(fieldName.getValue());
2424 parser.emitError(parser.getNameLoc(),
"invalid field name specified");
2427 result.addTypes(resultType);
2429 if (parser.resolveOperand(operand, declType, result.operands))
2436 template <
typename AggType>
2439 printer.printOperand(op.getInput());
2440 printer <<
"[\"" << op.getField() <<
"\"]";
2441 printer.printOptionalAttrDict(op->getAttrs(), {
"field"});
2442 printer <<
" : " << op.getInput().getType();
2445 ParseResult StructExtractOp::parse(OpAsmParser &parser,
2446 OperationState &result) {
2447 return parseExtractOp<StructType>(parser, result);
2450 void StructExtractOp::print(OpAsmPrinter &printer) {
2454 void StructExtractOp::build(OpBuilder &
builder, OperationState &odsState,
2455 Value input, StructType::FieldInfo field) {
2456 build(
builder, odsState, field.type, input, field.name);
2459 void StructExtractOp::build(OpBuilder &
builder, OperationState &odsState,
2460 Value input, StringAttr fieldAttr) {
2461 auto structType = type_cast<StructType>(input.getType());
2462 auto resultType = structType.getFieldType(fieldAttr);
2463 build(
builder, odsState, resultType, input, fieldAttr);
2466 OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
2467 if (
auto constOperand = adaptor.getInput()) {
2469 auto operandType = type_cast<StructType>(getOperand().getType());
2470 auto fieldIdx = operandType.getFieldIndex(getField());
2471 auto operandAttr = llvm::cast<ArrayAttr>(constOperand);
2472 return operandAttr.getValue()[*fieldIdx];
2475 if (
auto foldResult =
2481 LogicalResult StructExtractOp::canonicalize(StructExtractOp op,
2482 PatternRewriter &rewriter) {
2483 auto inputOp = op.getInput().getDefiningOp();
2486 if (
auto structInject = dyn_cast_or_null<StructInjectOp>(inputOp)) {
2487 if (structInject.getField() != op.getField()) {
2488 rewriter.replaceOpWithNewOp<StructExtractOp>(
2489 op, op.getType(), structInject.getInput(), op.getField());
2498 function_ref<
void(Value, StringRef)> setNameFn) {
2499 auto structType = type_cast<StructType>(getInput().getType());
2500 for (
auto field : structType.getElements()) {
2501 if (field.name == getField()) {
2502 setNameFn(getResult(), field.name.str());
2512 ParseResult StructInjectOp::parse(OpAsmParser &parser, OperationState &result) {
2513 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
2514 OpAsmParser::UnresolvedOperand operand, val;
2515 StringAttr fieldName;
2518 if (parser.parseOperand(operand) || parser.parseLSquare() ||
2519 parser.parseAttribute(fieldName,
"field", result.attributes) ||
2520 parser.parseRSquare() || parser.parseComma() ||
2521 parser.parseOperand(val) ||
2522 parser.parseOptionalAttrDict(result.attributes) ||
2523 parser.parseColonType(declType))
2525 auto structType = type_dyn_cast<StructType>(declType);
2527 return parser.emitError(inputOperandsLoc,
"invalid kind of type specified");
2529 Type resultType = structType.getFieldType(fieldName.getValue());
2531 parser.emitError(inputOperandsLoc,
"invalid field name specified");
2534 result.addTypes(declType);
2536 if (parser.resolveOperands({operand, val}, {declType, resultType},
2537 inputOperandsLoc, result.operands))
2542 void StructInjectOp::print(OpAsmPrinter &printer) {
2544 printer.printOperand(getInput());
2545 printer <<
"[\"" << getField() <<
"\"], ";
2546 printer.printOperand(getNewValue());
2547 printer.printOptionalAttrDict((*this)->getAttrs(), {
"field"});
2548 printer <<
" : " << getInput().getType();
2551 OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
2552 auto input = adaptor.getInput();
2553 auto newValue = adaptor.getNewValue();
2554 if (!input || !newValue)
2556 SmallVector<Attribute> array;
2557 llvm::copy(input.cast<ArrayAttr>(), std::back_inserter(array));
2558 StructType structType = getInput().getType();
2559 auto index = *structType.getFieldIndex(getField());
2560 array[index] = newValue;
2564 LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
2565 PatternRewriter &rewriter) {
2567 SmallPtrSet<Operation *, 4> injects;
2568 DenseMap<StringAttr, Value> fields;
2571 StructInjectOp inject = op;
2574 if (!injects.insert(inject).second)
2577 fields.try_emplace(inject.getFieldAttr(), inject.getNewValue());
2578 input = inject.getInput();
2579 inject = dyn_cast_or_null<StructInjectOp>(input.getDefiningOp());
2581 assert(input &&
"missing input to inject chain");
2583 auto ty = hw::type_cast<StructType>(op.getType());
2584 auto elements = ty.getElements();
2587 if (fields.size() == elements.size()) {
2588 SmallVector<Value> createFields;
2589 for (
const auto &field : elements) {
2590 auto it = fields.find(field.name);
2591 assert(it != fields.end() &&
"missing field");
2592 createFields.push_back(it->second);
2594 rewriter.replaceOpWithNewOp<StructCreateOp>(op, ty, createFields);
2599 if (injects.size() == fields.size())
2603 for (
const auto &field : elements) {
2604 auto it = fields.find(field.name);
2605 if (it == fields.end())
2607 input = rewriter.create<StructInjectOp>(op.getLoc(), ty, input, field.name,
2611 rewriter.replaceOp(op, input);
2619 ParseResult UnionCreateOp::parse(OpAsmParser &parser, OperationState &result) {
2620 Type declOrAliasType;
2622 OpAsmParser::UnresolvedOperand input;
2623 llvm::SMLoc fieldLoc = parser.getCurrentLocation();
2625 if (parser.parseAttribute(field,
"field", result.attributes) ||
2626 parser.parseComma() || parser.parseOperand(input) ||
2627 parser.parseOptionalAttrDict(result.attributes) ||
2628 parser.parseColonType(declOrAliasType))
2631 auto declType = type_dyn_cast<UnionType>(declOrAliasType);
2633 return parser.emitError(parser.getNameLoc(),
2634 "expected !hw.union type or alias");
2636 Type inputType = declType.getFieldType(field.getValue());
2638 parser.emitError(fieldLoc,
"cannot find union field '")
2639 << field.getValue() <<
'\'';
2643 if (parser.resolveOperand(input, inputType, result.operands))
2645 result.addTypes({declOrAliasType});
2649 void UnionCreateOp::print(OpAsmPrinter &printer) {
2650 printer <<
" \"" << getField() <<
"\", ";
2651 printer.printOperand(getInput());
2652 printer.printOptionalAttrDict((*this)->getAttrs(), {
"field"});
2653 printer <<
" : " << getType();
2660 ParseResult UnionExtractOp::parse(OpAsmParser &parser, OperationState &result) {
2661 return parseExtractOp<UnionType>(parser, result);
2664 void UnionExtractOp::print(OpAsmPrinter &printer) {
2669 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
2670 DictionaryAttr attrs, mlir::OpaqueProperties properties,
2671 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
2673 .getFieldType(attrs.getAs<StringAttr>(
"field")));
2686 OpFoldResult ArrayGetOp::fold(FoldAdaptor adaptor) {
2687 auto inputCst = adaptor.getInput().dyn_cast_or_null<ArrayAttr>();
2688 auto indexCst = adaptor.getIndex().dyn_cast_or_null<IntegerAttr>();
2693 auto indexVal = indexCst.getValue();
2694 if (indexVal.getBitWidth() < 64) {
2695 auto index = indexVal.getZExtValue();
2696 return inputCst[inputCst.size() - 1 - index];
2701 if (!inputCst.empty() && llvm::all_equal(inputCst))
2706 if (
auto bitcast = getInput().getDefiningOp<hw::BitcastOp>()) {
2707 auto intTy = getType().dyn_cast<IntegerType>();
2710 auto bitcastInputOp = bitcast.getInput().getDefiningOp<hw::ConstantOp>();
2711 if (!bitcastInputOp)
2715 auto bitcastInputCst = bitcastInputOp.getValue();
2718 auto startIdx = indexCst.getValue().zext(bitcastInputCst.getBitWidth()) *
2719 getType().getIntOrFloatBitWidth();
2722 intTy.getIntOrFloatBitWidth()));
2725 auto inputCreate = getInput().getDefiningOp<ArrayCreateOp>();
2729 if (
auto uniformValue = inputCreate.getUniformElement())
2730 return uniformValue;
2732 if (!indexCst || indexCst.getValue().getBitWidth() > 64)
2735 uint64_t index = indexCst.getValue().getLimitedValue();
2736 auto createInputs = inputCreate.getInputs();
2737 if (index >= createInputs.size())
2739 return createInputs[createInputs.size() - index - 1];
2742 LogicalResult ArrayGetOp::canonicalize(ArrayGetOp op,
2743 PatternRewriter &rewriter) {
2748 auto *inputOp = op.getInput().getDefiningOp();
2749 if (
auto inputSlice = dyn_cast_or_null<ArraySliceOp>(inputOp)) {
2751 auto offsetOp = inputSlice.getLowIndex();
2756 uint64_t offset = *offsetOpt + *idxOpt;
2758 rewriter.create<ConstantOp>(op.getLoc(), offsetOp.getType(), offset);
2759 rewriter.replaceOpWithNewOp<ArrayGetOp>(op, inputSlice.getInput(),
2764 if (
auto inputConcat = dyn_cast_or_null<ArrayConcatOp>(inputOp)) {
2766 uint64_t elemIndex = *idxOpt;
2767 for (
auto input : llvm::reverse(inputConcat.getInputs())) {
2768 size_t size = hw::type_cast<ArrayType>(input.getType()).getNumElements();
2769 if (elemIndex >=
size) {
2774 unsigned indexWidth =
size == 1 ? 1 : llvm::Log2_64_Ceil(
size);
2775 auto newIdxOp = rewriter.create<ConstantOp>(
2776 op.getLoc(), rewriter.getIntegerType(indexWidth), elemIndex);
2778 rewriter.replaceOpWithNewOp<ArrayGetOp>(op, input, newIdxOp);
2787 if (
auto innerGet = dyn_cast_or_null<hw::ArrayGetOp>(inputOp)) {
2788 if (!innerGet.getIndex().getDefiningOp<hw::ConstantOp>()) {
2790 innerGet.getInput().getDefiningOp<hw::ArrayCreateOp>()) {
2792 SmallVector<Value> newValues;
2793 for (
auto operand : create.getOperands())
2794 newValues.push_back(rewriter.createOrFold<hw::ArrayGetOp>(
2795 op.getLoc(), operand, op.getIndex()));
2797 rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(
2799 rewriter.createOrFold<hw::ArrayCreateOp>(op.getLoc(), newValues),
2800 innerGet.getIndex());
2813 StringRef TypedeclOp::getPreferredName() {
2814 return getVerilogName().value_or(
getName());
2817 Type TypedeclOp::getAliasType() {
2818 auto parentScope = cast<hw::TypeScopeOp>(getOperation()->getParentOp());
2821 {FlatSymbolRefAttr::get(*this)}),
2829 OpFoldResult BitcastOp::fold(FoldAdaptor) {
2832 if (getOperand().getType() == getType())
2833 return getOperand();
2838 LogicalResult BitcastOp::canonicalize(BitcastOp op, PatternRewriter &rewriter) {
2844 dyn_cast_or_null<BitcastOp>(op.getInput().getDefiningOp());
2847 auto bitcast = rewriter.createOrFold<BitcastOp>(op.getLoc(), op.getType(),
2848 inputBitcast.getInput());
2849 rewriter.replaceOp(op, bitcast);
2853 LogicalResult BitcastOp::verify() {
2855 return this->emitOpError(
"Bitwidth of input must match result");
2863 bool HierPathOp::dropModule(StringAttr moduleToDrop) {
2864 SmallVector<Attribute, 4> newPath;
2865 bool updateMade =
false;
2866 for (
auto nameRef : getNamepath()) {
2868 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>()) {
2869 if (ref.getModule() == moduleToDrop)
2872 newPath.push_back(ref);
2874 if (nameRef.cast<FlatSymbolRefAttr>().getAttr() == moduleToDrop)
2877 newPath.push_back(nameRef);
2885 bool HierPathOp::inlineModule(StringAttr moduleToDrop) {
2886 SmallVector<Attribute, 4> newPath;
2887 bool updateMade =
false;
2888 StringRef inlinedInstanceName =
"";
2889 for (
auto nameRef : getNamepath()) {
2891 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>()) {
2892 if (ref.getModule() == moduleToDrop) {
2893 inlinedInstanceName = ref.getName().getValue();
2895 }
else if (!inlinedInstanceName.empty()) {
2899 ref.getName().getValue())));
2900 inlinedInstanceName =
"";
2902 newPath.push_back(ref);
2904 if (nameRef.cast<FlatSymbolRefAttr>().getAttr() == moduleToDrop)
2907 newPath.push_back(nameRef);
2915 bool HierPathOp::updateModule(StringAttr oldMod, StringAttr newMod) {
2916 SmallVector<Attribute, 4> newPath;
2917 bool updateMade =
false;
2918 for (
auto nameRef : getNamepath()) {
2920 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>()) {
2921 if (ref.getModule() == oldMod) {
2925 newPath.push_back(ref);
2927 if (nameRef.cast<FlatSymbolRefAttr>().getAttr() == oldMod) {
2931 newPath.push_back(nameRef);
2939 bool HierPathOp::updateModuleAndInnerRef(
2940 StringAttr oldMod, StringAttr newMod,
2941 const llvm::DenseMap<StringAttr, StringAttr> &innerSymRenameMap) {
2943 if (oldMod == newMod)
2946 auto namepathNew = getNamepath().getValue().vec();
2947 bool updateMade =
false;
2949 for (
auto &element : namepathNew) {
2950 if (
auto innerRef = element.dyn_cast<hw::InnerRefAttr>()) {
2951 if (innerRef.getModule() != oldMod)
2953 auto symName = innerRef.getName();
2956 auto to = innerSymRenameMap.find(symName);
2957 if (to != innerSymRenameMap.end())
2958 symName = to->second;
2963 if (element != fromRef)
2975 bool HierPathOp::truncateAtModule(StringAttr atMod,
bool includeMod) {
2976 SmallVector<Attribute, 4> newPath;
2977 bool updateMade =
false;
2978 for (
auto nameRef : getNamepath()) {
2980 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>()) {
2981 if (ref.getModule() == atMod) {
2984 newPath.push_back(ref);
2986 newPath.push_back(ref);
2988 if (nameRef.cast<FlatSymbolRefAttr>().getAttr() == atMod && !includeMod)
2991 newPath.push_back(nameRef);
3002 StringAttr HierPathOp::modPart(
unsigned i) {
3003 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3004 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
3005 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
3009 StringAttr HierPathOp::root() {
3015 bool HierPathOp::hasModule(StringAttr modName) {
3016 for (
auto nameRef : getNamepath()) {
3018 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>()) {
3019 if (ref.getModule() == modName)
3022 if (nameRef.cast<FlatSymbolRefAttr>().getAttr() == modName)
3030 bool HierPathOp::hasInnerSym(StringAttr modName, StringAttr symName)
const {
3031 for (
auto nameRef :
const_cast<HierPathOp *
>(
this)->getNamepath())
3032 if (
auto ref = nameRef.dyn_cast<hw::InnerRefAttr>())
3033 if (ref.getName() == symName && ref.getModule() == modName)
3041 StringAttr HierPathOp::refPart(
unsigned i) {
3042 return TypeSwitch<Attribute, StringAttr>(getNamepath()[i])
3043 .Case<FlatSymbolRefAttr>([](
auto a) {
return StringAttr({}); })
3044 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getName(); });
3049 StringAttr HierPathOp::ref() {
3051 return refPart(getNamepath().
size() - 1);
3055 StringAttr HierPathOp::leafMod() {
3057 return modPart(getNamepath().
size() - 1);
3062 bool HierPathOp::isModule() {
return !ref(); }
3066 bool HierPathOp::isComponent() {
return (
bool)ref(); }
3081 LogicalResult HierPathOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
3082 StringAttr expectedModuleName = {};
3083 if (!getNamepath() || getNamepath().
empty())
3084 return emitOpError() <<
"the instance path cannot be empty";
3085 for (
unsigned i = 0, s = getNamepath().
size() - 1; i < s; ++i) {
3086 hw::InnerRefAttr innerRef = getNamepath()[i].dyn_cast<hw::InnerRefAttr>();
3088 return emitOpError()
3089 <<
"the instance path can only contain inner sym reference"
3090 <<
", only the leaf can refer to a module symbol";
3092 if (expectedModuleName && expectedModuleName != innerRef.getModule())
3093 return emitOpError() <<
"instance path is incorrect. Expected module: "
3094 << expectedModuleName
3095 <<
" instead found: " << innerRef.getModule();
3096 auto instOp = ns.lookupOp<igraph::InstanceOpInterface>(innerRef);
3098 return emitOpError() <<
" module: " << innerRef.getModule()
3099 <<
" does not contain any instance with symbol: "
3100 << innerRef.getName();
3101 expectedModuleName = instOp.getReferencedModuleNameAttr();
3104 auto leafRef = getNamepath()[getNamepath().size() - 1];
3105 if (
auto innerRef = leafRef.dyn_cast<hw::InnerRefAttr>()) {
3106 if (!ns.lookup(innerRef)) {
3107 return emitOpError() <<
" operation with symbol: " << innerRef
3108 <<
" was not found ";
3110 if (expectedModuleName && expectedModuleName != innerRef.getModule())
3111 return emitOpError() <<
"instance path is incorrect. Expected module: "
3112 << expectedModuleName
3113 <<
" instead found: " << innerRef.getModule();
3114 }
else if (expectedModuleName &&
3115 expectedModuleName !=
3116 leafRef.cast<FlatSymbolRefAttr>().getAttr()) {
3118 return emitOpError() <<
"instance path is incorrect. Expected module: "
3119 << expectedModuleName <<
" instead found: "
3120 << leafRef.cast<FlatSymbolRefAttr>().
getAttr();
3125 void HierPathOp::print(OpAsmPrinter &p) {
3129 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
3130 if (
auto visibility =
3131 getOperation()->getAttrOfType<StringAttr>(visibilityAttrName))
3132 p << visibility.getValue() <<
' ';
3134 p.printSymbolName(getSymName());
3136 llvm::interleaveComma(getNamepath().getValue(), p, [&](Attribute attr) {
3137 if (
auto ref = attr.dyn_cast<hw::InnerRefAttr>()) {
3138 p.printSymbolName(ref.getModule().getValue());
3140 p.printSymbolName(ref.getName().getValue());
3142 p.printSymbolName(attr.cast<FlatSymbolRefAttr>().getValue());
3146 p.printOptionalAttrDict(
3147 (*this)->getAttrs(),
3148 {SymbolTable::getSymbolAttrName(),
"namepath", visibilityAttrName});
3151 ParseResult HierPathOp::parse(OpAsmParser &parser, OperationState &result) {
3153 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
3157 if (parser.parseSymbolName(symName, SymbolTable::getSymbolAttrName(),
3162 SmallVector<Attribute> namepath;
3163 if (parser.parseCommaSeparatedList(
3164 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
3165 auto loc = parser.getCurrentLocation();
3167 if (parser.parseAttribute(ref))
3171 auto pathLength = ref.getNestedReferences().size();
3172 if (pathLength == 0)
3174 FlatSymbolRefAttr::get(ref.getRootReference()));
3175 else if (pathLength == 1)
3176 namepath.push_back(hw::InnerRefAttr::get(ref.getRootReference(),
3177 ref.getLeafReference()));
3179 return parser.emitError(loc,
3180 "only one nested reference is allowed");
3184 result.addAttribute(
"namepath",
3187 if (parser.parseOptionalAttrDict(result.attributes))
3197 void TriggeredOp::build(OpBuilder &
builder, OperationState &odsState,
3198 EventControlAttr event, Value trigger,
3200 odsState.addOperands(trigger);
3201 odsState.addOperands(
inputs);
3202 odsState.addAttribute(getEventAttrName(odsState.name), event);
3203 auto *r = odsState.addRegion();
3207 llvm::SmallVector<Location> argLocs;
3208 llvm::transform(
inputs, std::back_inserter(argLocs),
3209 [&](Value v) {
return v.getLoc(); });
3210 b->addArguments(
inputs.getTypes(), argLocs);
3219 SmallVectorImpl<module_like_impl::PortParse> &ports,
3220 StringAttr portAttrsName, StringAttr portLocsName) {
3221 auto unknownLoc =
builder.getUnknownLoc();
3222 auto nonEmptyAttrsFn = [](Attribute attr) {
3223 return attr && !cast<DictionaryAttr>(attr).empty();
3225 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
3226 return attr && cast<Location>(attr) != unknownLoc;
3231 SmallVector<Attribute> attrs;
3232 SmallVector<Attribute> locs;
3233 for (
auto &port : ports) {
3234 attrs.push_back(port.attrs ? port.attrs :
builder.getDictionaryAttr({}));
3235 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
3239 if (llvm::any_of(attrs, nonEmptyAttrsFn))
3240 result.addAttribute(portAttrsName,
builder.getArrayAttr(attrs));
3242 if (llvm::any_of(locs, nonEmptyLocsFn))
3243 result.addAttribute(portLocsName,
builder.getArrayAttr(locs));
3246 void HWTestModuleOp::print(OpAsmPrinter &p) {
3249 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
3250 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
3251 p << visibility.getValue() <<
' ';
3254 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
3260 SmallVector<StringRef, 3> omittedAttrs;
3261 omittedAttrs.push_back(getPortLocsAttrName());
3262 omittedAttrs.push_back(getModuleTypeAttrName());
3263 omittedAttrs.push_back(getPortAttrsAttrName());
3264 omittedAttrs.push_back(getParametersAttrName());
3265 omittedAttrs.push_back(visibilityAttrName);
3266 if (
auto cmt = (*this)->getAttrOfType<StringAttr>(
"comment"))
3267 if (cmt.getValue().empty())
3268 omittedAttrs.push_back(
"comment");
3270 mlir::function_interface_impl::printFunctionAttributes(p, *
this,
3274 Region &body = getBody();
3275 if (!body.empty()) {
3277 p.printRegion(body,
false,
3282 ParseResult HWTestModuleOp::parse(OpAsmParser &parser, OperationState &result) {
3283 auto loc = parser.getCurrentLocation();
3286 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
3289 StringAttr nameAttr;
3290 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
3295 ArrayAttr parameters;
3299 SmallVector<module_like_impl::PortParse> ports;
3305 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
3309 parser.emitError(loc,
"explicit `parameters` attributes not allowed");
3313 result.addAttribute(
"parameters", parameters);
3314 result.addAttribute(getModuleTypeAttrName(result.name), modType);
3316 getPortAttrsAttrName(result.name),
3317 getPortLocsAttrName(result.name));
3319 SmallVector<OpAsmParser::Argument, 4> entryArgs;
3320 for (
auto &port : ports)
3322 entryArgs.push_back(port);
3325 auto *body = result.addRegion();
3326 if (parser.parseRegion(*body, entryArgs))
3329 HWModuleOp::ensureTerminator(*body, parser.getBuilder(), result.location);
3334 void HWTestModuleOp::getAsmBlockArgumentNames(
3339 auto *block = ®ion.front();
3341 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
3342 auto name = mt.getInputName(i);
3344 setNameFn(block->getArgument(i), name);
3349 SmallVector<PortInfo> ports;
3351 for (
auto [i, port] : enumerate(refPorts)) {
3352 auto loc = getPortLocs() ? cast<LocationAttr>((*getPortLocs())[i])
3354 auto attr = getPortAttrs() ? cast<DictionaryAttr>((*getPortAttrs())[i])
3356 InnerSymAttr sym = {};
3357 ports.push_back({{port}, i, sym, attr, loc});
3359 return ModulePortInfo(ports);
3363 size_t HWTestModuleOp::getNumInputPorts() {
3366 size_t HWTestModuleOp::getNumOutputPorts() {
3370 size_t HWTestModuleOp::getPortIdForInputId(
size_t idx) {
3374 size_t HWTestModuleOp::getPortIdForOutputId(
size_t idx) {
3378 hw::InnerSymAttr HWTestModuleOp::getPortSymbolAttr(
size_t portIndex) {
3379 auto pa = getPortAttrs();
3381 return cast<hw::InnerSymAttr>((*pa)[portIndex]);
3390 #define GET_OP_CLASSES
3391 #include "circt/Dialect/HW/HW.cpp.inc"
assert(baseType &&"element must be base type")
static Attribute getAttr(ArrayRef< NamedAttribute > attrs, StringRef name)
Get an attribute by name from a list of named attributes.
static LogicalResult verifyModuleCommon(HWModuleLike module)
static void printParamValue(OpAsmPrinter &p, Operation *, Attribute value, Type resultType)
static void addArgAndResultAttrsHW(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs)
static void printModuleOp(OpAsmPrinter &p, ModuleTy mod)
static bool flattenConcatOp(ArrayConcatOp op, PatternRewriter &rewriter)
static LogicalResult foldCreateToSlice(ArrayCreateOp op, PatternRewriter &rewriter)
static SmallVector< Location > getAllPortLocs(ModTy module)
static void addPortAttrsAndLocs(Builder &builder, OperationState &result, SmallVectorImpl< module_like_impl::PortParse > &ports, StringAttr portAttrsName, StringAttr portLocsName)
static ArrayAttr arrayOrEmpty(mlir::MLIRContext *context, ArrayRef< Attribute > attrs)
FunctionType getHWModuleOpType(Operation *op)
static Attribute getAttribute(StringRef name, ArrayRef< NamedAttribute > attrs)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, const ModulePortInfo &ports, ArrayAttr parameters, ArrayRef< NamedAttribute > attributes, StringAttr comment)
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 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 parseSliceTypes(OpAsmParser &p, Type &srcType, Type &idxType)
static bool hasAttribute(StringRef name, ArrayRef< NamedAttribute > attrs)
static bool mergeConcatSlices(ArrayConcatOp op, PatternRewriter &rewriter)
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 ModulePortInfo getPortList(ModuleTy &mod)
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 std::optional< uint64_t > getUIntFromValue(Value value)
static Value foldStructExtract(Operation *inputOp, StringRef field)
static InnerSymAttr extractSym(DictionaryAttr attrs)
static ParseResult parseHWModuleOp(OpAsmParser &parser, OperationState &result, ExternModKind modKind=PlainMod)
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 void setAllPortLocs(ArrayRef< Location > locs, ModTy module)
static ParseResult parseArrayConcatTypes(OpAsmParser &p, SmallVectorImpl< Type > &inputTypes, Type &resultType)
static InstancePath empty
llvm::SmallVector< StringAttr > inputs
llvm::SmallVector< StringAttr > outputs
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static size_t bits(::capnp::schema::Type::Reader type)
Return the number of bits used by a Capnp type.
static int64_t size(hw::ArrayType mType, capnp::schema::Field::Reader cField)
Returns the expected size of an array (capnp list) in 64-bit words.
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)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
LogicalResult inferReturnTypes(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results, llvm::function_ref< FIRRTLType(ValueRange, ArrayRef< NamedAttribute >, std::optional< Location >)> callback)
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.
ArrayAttr updateName(ArrayAttr oldNames, size_t i, StringAttr name)
Change the name at the specified index of the.
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
void printModuleSignature(OpAsmPrinter &p, Operation *op, ArrayRef< Type > argTypes, bool isVariadic, ArrayRef< Type > resultTypes, bool &needArgNamesAttr)
Print a module signature with named results.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
ParseResult parseModuleFunctionSignature(OpAsmParser &parser, bool &isVariadic, SmallVectorImpl< OpAsmParser::Argument > &args, SmallVectorImpl< Attribute > &argNames, SmallVectorImpl< Attribute > &argLocs, SmallVectorImpl< Attribute > &resultNames, SmallVectorImpl< DictionaryAttr > &resultAttrs, SmallVectorImpl< Attribute > &resultLocs, TypeAttr &type)
This is a variant of mlir::parseFunctionSignature that allows names on result arguments.
void printModuleSignatureNew(OpAsmPrinter &p, Operation *op)
bool isOffset(Value base, Value index, uint64_t offset)
llvm::function_ref< void(OpBuilder &, HWModulePortAccessor &)> HWModuleBuilder
bool isCombinational(Operation *op)
Return true if the specified operation is a combinational logic op.
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)
TODO: Move all these functions to a hw::ModuleLike interface.
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.
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...
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...
bool isValidIndexBitWidth(Value index, Value array)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
bool isAnyModuleOrInstance(Operation *module)
Return true if isAnyModule or instance.
StringAttr getVerilogModuleNameAttr(Operation *module)
Returns the verilog module name attribute or symbol name of any module-like operations.
mlir::Type getCanonicalType(mlir::Type type)
circt::hw::InOutType InOutType
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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.
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 holds a decoded list of input/inout and output ports for a module or instance.
size_t sizeOutputs() const
PortInfo & at(size_t idx)
size_t sizeInputs() const
PortDirectionRange getOutputs()