18#include "mlir/IR/Builders.h"
19#include "llvm/ADT/APSInt.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include <mlir/Dialect/Func/IR/FuncOps.h>
32void SVModuleOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
33 llvm::StringRef name, hw::ModuleType type) {
34 state.addAttribute(SymbolTable::getSymbolAttrName(),
35 builder.getStringAttr(name));
36 state.addAttribute(getModuleTypeAttrName(state.name), TypeAttr::get(type));
40void SVModuleOp::print(OpAsmPrinter &p) {
44 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
45 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
46 p << visibility.getValue() <<
' ';
48 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
52 p.printRegion(getBodyRegion(),
false,
55 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
59ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
61 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
65 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
70 SmallVector<hw::module_like_impl::PortParse> ports;
75 result.addAttribute(getModuleTypeAttrName(result.name), modType);
78 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
82 SmallVector<OpAsmParser::Argument, 4> entryArgs;
83 for (
auto &port : ports)
85 entryArgs.push_back(port);
88 auto &bodyRegion = *result.addRegion();
89 if (parser.parseRegion(bodyRegion, entryArgs))
92 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
96void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
98 if (®ion != &getBodyRegion())
101 for (
auto [index, arg] :
llvm::enumerate(region.front().getArguments()))
102 setNameFn(arg, moduleType.getInputNameAttr(index));
105OutputOp SVModuleOp::getOutputOp() {
106 return cast<OutputOp>(getBody()->getTerminator());
109OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
115LogicalResult OutputOp::verify() {
116 auto module = getParentOp();
119 auto outputTypes =
module.getModuleType().getOutputTypes();
120 if (outputTypes.size() != getNumOperands())
121 return emitOpError(
"has ")
122 << getNumOperands() <<
" operands, but enclosing module @"
123 <<
module.getSymName() << " has " << outputTypes.size()
127 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
128 if (outputTypes[i] != getOperand(i).getType())
129 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
130 <<
") does not match output type (" << outputTypes[i]
131 <<
") of module @" <<
module.getSymName();
140LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
143 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
145 return emitOpError(
"references unknown symbol @") << getModuleName();
148 auto module = dyn_cast<SVModuleOp>(symbol);
150 return emitOpError(
"must reference a 'moore.module', but @")
151 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
154 auto moduleType =
module.getModuleType();
155 auto inputTypes = moduleType.getInputTypes();
157 if (inputTypes.size() != getNumOperands())
158 return emitOpError(
"has ")
159 << getNumOperands() <<
" operands, but target module @"
160 <<
module.getSymName() << " has " << inputTypes.size() << " inputs";
162 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
163 if (inputTypes[i] != getOperand(i).getType())
164 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
165 <<
") does not match input type (" << inputTypes[i]
166 <<
") of module @" <<
module.getSymName();
169 auto outputTypes = moduleType.getOutputTypes();
171 if (outputTypes.size() != getNumResults())
172 return emitOpError(
"has ")
173 << getNumOperands() <<
" results, but target module @"
174 <<
module.getSymName() << " has " << outputTypes.size()
177 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
178 if (outputTypes[i] != getResult(i).getType())
179 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
180 <<
") does not match output type (" << outputTypes[i]
181 <<
") of module @" <<
module.getSymName();
186void InstanceOp::print(OpAsmPrinter &p) {
188 p.printAttributeWithoutType(getInstanceNameAttr());
190 p.printAttributeWithoutType(getModuleNameAttr());
196 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
199ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
201 StringAttr instanceName;
202 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
206 FlatSymbolRefAttr moduleName;
207 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
211 auto loc = parser.getCurrentLocation();
212 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
213 SmallVector<Type> types;
217 if (parser.resolveOperands(inputs, types, loc, result.operands))
219 result.addAttribute(
"inputNames", names);
222 if (parser.parseArrow())
229 result.addAttribute(
"outputNames", names);
230 result.addTypes(types);
233 if (parser.parseOptionalAttrDict(result.attributes))
240 SmallString<32> name;
243 auto baseLen = name.size();
245 for (
auto [result, portName] :
246 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
247 if (!portName || portName.empty())
249 name.resize(baseLen);
250 name += portName.getValue();
251 setNameFn(result, name);
261 setNameFn(getResult(), *
getName());
264LogicalResult VariableOp::canonicalize(VariableOp op,
265 PatternRewriter &rewriter) {
269 auto initial = op.getInitial();
270 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
271 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
272 rewriter.setInsertionPointAfter(op);
273 BlockingAssignOp::create(rewriter, initial.getLoc(), op, initial);
280 auto *block = op->getBlock();
281 ContinuousAssignOp uniqueAssignOp;
282 for (
auto *user : op->getUsers()) {
284 if (user->getBlock() != block)
288 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
291 uniqueAssignOp = assignOp;
296 if (!isa<ReadOp>(user))
304 Value assignedValue = uniqueAssignOp.getSrc();
305 if (
auto name = op.getNameAttr(); name && !name.empty())
306 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
307 uniqueAssignOp.getSrc());
310 rewriter.eraseOp(uniqueAssignOp);
311 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
312 auto readOp = cast<ReadOp>(user);
313 rewriter.replaceOp(readOp, assignedValue);
317 rewriter.eraseOp(op);
321SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
324 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
330 auto nestedType = dyn_cast<PackedType>(getType().getNestedType());
331 if (!nestedType || !nestedType.getBitSize())
334 return {MemorySlot{getResult(), getType().getNestedType()}};
337Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
338 auto packedType = dyn_cast<PackedType>(slot.elemType);
341 auto bitWidth = packedType.getBitSize();
344 auto fvint = packedType.getDomain() == Domain::FourValued
346 :
FVInt::getZero(*bitWidth);
347 Value value = ConstantOp::create(
349 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
350 if (value.getType() != packedType)
351 SBVToPackedOp::create(builder,
getLoc(), packedType, value);
355void VariableOp::handleBlockArgument(
const MemorySlot &slot,
356 BlockArgument argument,
357 OpBuilder &builder) {}
359std::optional<mlir::PromotableAllocationOpInterface>
360VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
361 OpBuilder &builder) {
362 if (defaultValue && defaultValue.use_empty())
363 defaultValue.getDefiningOp()->erase();
368SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
369 if (isa<SVModuleOp>(getOperation()->getParentOp()))
374 auto refType = getType();
375 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
379 auto destructuredType = destructurable.getSubelementIndexMap();
380 if (!destructuredType)
383 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
386DenseMap<Attribute, MemorySlot> VariableOp::destructure(
387 const DestructurableMemorySlot &slot,
388 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
389 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
390 assert(slot.ptr == getResult());
392 builder.setInsertionPointAfter(*
this);
394 auto destructurableType = cast<DestructurableTypeInterface>(getType());
395 DenseMap<Attribute, MemorySlot> slotMap;
396 for (Attribute index : usedIndices) {
397 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
398 assert(elemType &&
"used index must exist");
400 if (
auto name =
getName(); name && !name->empty())
401 varName = StringAttr::get(
402 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
404 VariableOp::create(builder,
getLoc(), elemType, varName, Value());
405 newAllocators.push_back(varOp);
406 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
412std::optional<DestructurableAllocationOpInterface>
413VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
414 OpBuilder &builder) {
415 assert(slot.ptr == getResult());
426 setNameFn(getResult(), *
getName());
429LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
430 bool modified =
false;
434 auto *block = op->getBlock();
435 ContinuousAssignOp uniqueAssignOp;
436 bool allUsesAreReads =
true;
437 for (
auto *user : op->getUsers()) {
439 if (user->getBlock() != block)
443 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
446 uniqueAssignOp = assignOp;
451 if (!isa<ReadOp>(user))
452 allUsesAreReads =
false;
457 if (uniqueAssignOp && !op.getAssignment()) {
458 rewriter.modifyOpInPlace(
459 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
460 rewriter.eraseOp(uniqueAssignOp);
468 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
471 auto assignedValue = op.getAssignment();
472 if (
auto name = op.getNameAttr(); name && !name.empty())
473 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
478 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
479 auto readOp = cast<ReadOp>(user);
480 rewriter.replaceOp(readOp, assignedValue);
482 rewriter.eraseOp(op);
486 return success(modified);
495 setNameFn(getResult(), *
getName());
498LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
499 PatternRewriter &rewriter) {
502 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
503 if (otherOp.getNameAttr() == op.getNameAttr()) {
504 rewriter.replaceOp(op, otherOp);
510 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
512 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
513 auto moduleType = moduleOp.getModuleType();
514 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
515 if (portName == op.getNameAttr()) {
516 rewriter.replaceOp(op, blockArg);
523 for (
auto &use : op->getUses()) {
524 auto *useOwner = use.getOwner();
525 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
526 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
527 auto moduleType = moduleOp.getModuleType();
528 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
529 if (portName == op.getNameAttr()) {
530 rewriter.replaceOp(op, op.getInput());
545LogicalResult GlobalVariableOp::verifyRegions() {
546 if (
auto *block = getInitBlock()) {
547 auto &terminator = block->back();
548 if (!isa<YieldOp>(terminator))
549 return emitOpError() <<
"must have a 'moore.yield' terminator";
554Block *GlobalVariableOp::getInitBlock() {
555 if (getInitRegion().
empty())
557 return &getInitRegion().front();
565GetGlobalVariableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
568 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
570 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
573 auto var = dyn_cast<GlobalVariableOp>(symbol);
575 return emitOpError() <<
"must reference a 'moore.global_variable', but "
576 << getGlobalNameAttr() <<
" is a '"
577 << symbol->getName() <<
"'";
580 auto expType = var.getType();
581 auto actType = getType().getNestedType();
582 if (expType != actType)
583 return emitOpError() <<
"returns a " << actType <<
" reference, but "
584 << getGlobalNameAttr() <<
" is of type " << expType;
593void ConstantOp::print(OpAsmPrinter &p) {
596 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
598 p.printStrippedAttrOrType(getType());
601ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
604 auto valueLoc = parser.getCurrentLocation();
609 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
614 if (parser.parseCustomTypeWithFallback(type))
622 value = value.
sext(type.getWidth());
623 }
else if (type.getWidth() < value.
getBitWidth()) {
626 unsigned neededBits =
628 if (type.getWidth() < neededBits)
629 return parser.emitError(valueLoc)
630 <<
"value requires " << neededBits
631 <<
" bits, but result type only has " << type.getWidth();
632 value = value.
trunc(type.getWidth());
637 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
638 return parser.emitError(valueLoc)
639 <<
"value contains X or Z bits, but result type " << type
640 <<
" only allows two-valued bits";
643 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
644 result.addAttribute(
"value", attrValue);
645 result.addTypes(type);
649LogicalResult ConstantOp::verify() {
650 auto attrWidth = getValue().getBitWidth();
651 auto typeWidth = getType().getWidth();
652 if (attrWidth != typeWidth)
653 return emitError(
"attribute width ")
654 << attrWidth <<
" does not match return type's width " << typeWidth;
658void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
659 const FVInt &value) {
661 "FVInt width must match type width");
662 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
665void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
666 const APInt &value) {
667 assert(type.getWidth() == value.getBitWidth() &&
668 "APInt width must match type width");
669 build(builder, result, type,
FVInt(value));
676void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
677 int64_t value,
bool isSigned) {
678 build(builder, result, type,
679 APInt(type.getWidth(), (uint64_t)value, isSigned));
682OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
683 assert(adaptor.getOperands().empty() &&
"constant has no operands");
684 return getValueAttr();
691OpFoldResult ConstantTimeOp::fold(FoldAdaptor adaptor) {
692 return getValueAttr();
699LogicalResult ConstantRealOp::inferReturnTypes(
700 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
701 DictionaryAttr attrs, mlir::OpaqueProperties properties,
702 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
703 ConstantRealOp::Adaptor adaptor(operands, attrs, properties);
704 results.push_back(RealType::get(
706 adaptor.getValueAttr().getType().getIntOrFloatBitWidth())));
714LogicalResult ConcatOp::inferReturnTypes(
715 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
716 DictionaryAttr attrs, mlir::OpaqueProperties properties,
717 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
718 Domain domain = Domain::TwoValued;
720 for (
auto operand : operands) {
721 auto type = cast<IntType>(operand.getType());
722 if (type.getDomain() == Domain::FourValued)
723 domain = Domain::FourValued;
724 width += type.getWidth();
726 results.push_back(IntType::get(
context, width, domain));
734LogicalResult ConcatRefOp::inferReturnTypes(
735 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
736 DictionaryAttr attrs, mlir::OpaqueProperties properties,
737 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
738 Domain domain = Domain::TwoValued;
740 for (Value operand : operands) {
741 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
742 PackedType packedType = dyn_cast<PackedType>(nestedType);
748 if (packedType.
getDomain() == Domain::FourValued)
749 domain = Domain::FourValued;
752 std::optional<int> bitSize = packedType.
getBitSize();
758 results.push_back(RefType::get(IntType::get(
context, width, domain)));
767 if (
auto arrayType = dyn_cast<ArrayType>(type))
768 return {arrayType.getSize(), arrayType.getElementType()};
769 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
770 return {arrayType.getSize(), arrayType.getElementType()};
771 assert(0 &&
"expected ArrayType or UnpackedArrayType");
775LogicalResult ArrayCreateOp::verify() {
779 if (getElements().size() != size)
780 return emitOpError() <<
"has " << getElements().size()
781 <<
" operands, but result type requires " << size;
787 auto value = getElements()[0];
789 return emitOpError() <<
"operands have type " << value.getType()
800 if (
auto structType = dyn_cast<StructType>(type))
801 return structType.getFieldIndex(name);
802 if (
auto structType = dyn_cast<UnpackedStructType>(type))
803 return structType.getFieldIndex(name);
804 assert(0 &&
"expected StructType or UnpackedStructType");
809 if (
auto structType = dyn_cast<StructType>(type))
810 return structType.getMembers();
811 if (
auto structType = dyn_cast<UnpackedStructType>(type))
812 return structType.getMembers();
813 assert(0 &&
"expected StructType or UnpackedStructType");
823LogicalResult StructCreateOp::verify() {
827 if (getFields().size() != members.size())
828 return emitOpError() <<
"has " << getFields().size()
829 <<
" operands, but result type requires "
833 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
834 auto [value, member] = pair;
835 if (value.getType() != member.type)
836 return emitOpError() <<
"operand #" << index <<
" has type "
837 << value.getType() <<
", but struct field "
838 << member.name <<
" requires " << member.type;
843OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
844 SmallVector<NamedAttribute> fields;
845 for (
auto [member, field] :
849 fields.push_back(NamedAttribute(member.name, field));
851 return DictionaryAttr::get(getContext(), fields);
858LogicalResult StructExtractOp::verify() {
861 return emitOpError() <<
"extracts field " << getFieldNameAttr()
862 <<
" which does not exist in " << getInput().getType();
863 if (type != getType())
864 return emitOpError() <<
"result type " << getType()
865 <<
" must match struct field type " << type;
869OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
871 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
872 if (
auto value = fields.get(getFieldNameAttr()))
876 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
877 if (inject.getFieldNameAttr() == getFieldNameAttr())
878 return inject.getNewValue();
883 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
885 return create.getFields()[*index];
896LogicalResult StructExtractRefOp::verify() {
898 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
900 return emitOpError() <<
"extracts field " << getFieldNameAttr()
901 <<
" which does not exist in " << getInput().getType();
902 if (type != getType().getNestedType())
903 return emitOpError() <<
"result ref of type " << getType().getNestedType()
904 <<
" must match struct field type " << type;
908bool StructExtractRefOp::canRewire(
909 const DestructurableMemorySlot &slot,
910 SmallPtrSetImpl<Attribute> &usedIndices,
911 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
912 const DataLayout &dataLayout) {
913 if (slot.ptr != getInput())
915 auto index = getFieldNameAttr();
916 if (!index || !slot.subelementTypes.contains(index))
918 usedIndices.insert(index);
923StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
924 DenseMap<Attribute, MemorySlot> &subslots,
925 OpBuilder &builder,
const DataLayout &dataLayout) {
926 auto index = getFieldNameAttr();
927 const MemorySlot &memorySlot = subslots.at(index);
928 replaceAllUsesWith(memorySlot.ptr);
929 getInputMutable().drop();
931 return DeletionKind::Keep;
938LogicalResult StructInjectOp::verify() {
941 return emitOpError() <<
"injects field " << getFieldNameAttr()
942 <<
" which does not exist in " << getInput().getType();
943 if (type != getNewValue().getType())
944 return emitOpError() <<
"injected value " << getNewValue().getType()
945 <<
" must match struct field type " << type;
949OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
950 auto input = adaptor.getInput();
951 auto newValue = adaptor.getNewValue();
952 if (!input || !newValue)
954 NamedAttrList fields(cast<DictionaryAttr>(input));
955 fields.set(getFieldNameAttr(), newValue);
956 return fields.getDictionary(getContext());
959LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
960 PatternRewriter &rewriter) {
965 SmallPtrSet<Operation *, 4> injectOps;
966 DenseMap<StringAttr, Value> fieldValues;
968 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
969 if (!injectOps.insert(injectOp).second)
971 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
972 input = injectOp.getInput();
974 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
975 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
976 fieldValues.insert({member.name, value});
979 if (fieldValues.size() == members.size()) {
980 SmallVector<Value> values;
981 values.reserve(fieldValues.size());
982 for (
auto member : members)
983 values.push_back(fieldValues.lookup(member.name));
984 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
990 if (injectOps.size() == fieldValues.size())
995 for (
auto member : members)
996 if (auto value = fieldValues.lookup(member.name))
997 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
999 rewriter.replaceOp(op, input);
1007LogicalResult UnionCreateOp::verify() {
1010 return TypeSwitch<Type, LogicalResult>(getType())
1011 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1012 auto members = type.getMembers();
1013 auto inputType = getInput().getType();
1015 for (
const auto &member : members)
1016 if (member.name == fieldName && member.type == inputType)
1018 for (
const auto &member : members) {
1019 if (member.name == fieldName) {
1020 emitOpError() <<
"input type " << inputType
1021 <<
" does not match union field '" << fieldName
1022 <<
"' type " << member.type;
1026 emitOpError() <<
"field '" << fieldName <<
"' not found in union type";
1029 .Default([
this](
auto &) {
1030 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1039LogicalResult UnionExtractOp::verify() {
1042 return TypeSwitch<Type, LogicalResult>(getInput().getType())
1043 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1044 auto members = type.getMembers();
1046 auto resultType = getType();
1047 for (
const auto &member : members)
1048 if (member.name == fieldName && member.type == resultType)
1050 emitOpError(
"result type must match the union field type");
1053 .Default([
this](
auto &) {
1054 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1063LogicalResult UnionExtractRefOp::verify() {
1066 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1067 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1068 auto members = type.getMembers();
1070 auto resultType = getType().getNestedType();
1071 for (
const auto &member : members)
1072 if (member.name == fieldName && member.type == resultType)
1074 emitOpError(
"result type must match the union field type");
1077 .Default([
this](
auto &) {
1078 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1087LogicalResult YieldOp::verify() {
1089 auto *parentOp = getOperation()->getParentOp();
1090 if (
auto cond = dyn_cast<ConditionalOp>(parentOp)) {
1091 expType = cond.getType();
1092 }
else if (
auto varOp = dyn_cast<GlobalVariableOp>(parentOp)) {
1093 expType = varOp.getType();
1095 llvm_unreachable(
"all in ParentOneOf handled");
1098 auto actType = getOperand().getType();
1099 if (expType != actType) {
1100 return emitOpError() <<
"yields " << actType <<
", but parent expects "
1110OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1112 if (getInput().getType() == getResult().getType())
1116 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1117 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1118 auto toIntType = dyn_cast<IntType>(getResult().getType());
1119 if (intInput && fromIntType && toIntType &&
1120 fromIntType.getWidth() == toIntType.getWidth()) {
1123 if (toIntType.getDomain() == Domain::FourValued)
1128 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1138OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1140 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1141 return reverseOp.getInput();
1145 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1146 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1155OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1160 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1170OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1172 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1173 return reverseOp.getInput();
1176 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1177 return FVIntegerAttr::get(getContext(), attr.getValue());
1186OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1188 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1189 return reverseOp.getInput();
1192 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1193 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1203OpFoldResult ConvertRealOp::fold(FoldAdaptor adaptor) {
1204 if (getInput().getType() == getResult().getType())
1214OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1216 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1217 auto width = getType().getWidth();
1218 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1228OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1230 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1231 auto width = getType().getWidth();
1232 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1242OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1244 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1245 auto width = getType().getWidth();
1246 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1256OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1258 if (getInput().getType() == getResult().getType())
1267bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1269bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1270 return getDst() == slot.ptr;
1273Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1275 const DataLayout &dataLayout) {
1279bool BlockingAssignOp::canUsesBeRemoved(
1280 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1281 SmallVectorImpl<OpOperand *> &newBlockingUses,
1282 const DataLayout &dataLayout) {
1284 if (blockingUses.size() != 1)
1286 Value blockingUse = (*blockingUses.begin())->
get();
1287 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1288 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1291DeletionKind BlockingAssignOp::removeBlockingUses(
1292 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1293 OpBuilder &builder, Value reachingDefinition,
1294 const DataLayout &dataLayout) {
1295 return DeletionKind::Delete;
1302bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1303 return getInput() == slot.ptr;
1306bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1308Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1309 Value reachingDef,
const DataLayout &dataLayout) {
1310 llvm_unreachable(
"getStored should not be called on ReadOp");
1313bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1314 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1315 SmallVectorImpl<OpOperand *> &newBlockingUses,
1316 const DataLayout &dataLayout) {
1318 if (blockingUses.size() != 1)
1320 Value blockingUse = (*blockingUses.begin())->
get();
1321 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1322 getResult().getType() == slot.elemType;
1326ReadOp::removeBlockingUses(
const MemorySlot &slot,
1327 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1328 OpBuilder &builder, Value reachingDefinition,
1329 const DataLayout &dataLayout) {
1330 getResult().replaceAllUsesWith(reachingDefinition);
1331 return DeletionKind::Delete;
1340 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1341 if (lhsValue && lhsValue.getValue() == 1)
1344 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1345 if (rhsValue && rhsValue.getValue().isZero())
1346 return FVIntegerAttr::get(ctxt,
1347 FVInt(rhsValue.getValue().getBitWidth(), 1));
1352OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1356LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1357 Location loc = op.getLoc();
1358 auto intType = cast<IntType>(op.getRhs().getType());
1359 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1360 if (baseOp.getValue() == 2) {
1361 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1362 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1363 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1364 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1365 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1366 op, op.getLhs().getType(), isNegative);
1367 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1368 rewriter.setInsertionPointToStart(thenBlock);
1369 YieldOp::create(rewriter, loc, constZero);
1370 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1371 rewriter.setInsertionPointToStart(elseBlock);
1372 YieldOp::create(rewriter, loc, shift);
1384OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1388LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1389 Location loc = op.getLoc();
1390 auto intType = cast<IntType>(op.getRhs().getType());
1391 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1392 if (baseOp.getValue() == 2) {
1393 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1394 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1406OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1407 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1408 if (intAttr.getValue().isZero())
1418OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1419 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1420 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1422 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1430OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1431 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1432 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1434 return FVIntegerAttr::get(getContext(),
1435 lhs.getValue().udiv(rhs.getValue()));
1443OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1444 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1445 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1447 return FVIntegerAttr::get(getContext(),
1448 lhs.getValue().sdiv(rhs.getValue()));
1456LogicalResult ClassDeclOp::verify() {
1457 mlir::Region &body = getBody();
1459 return mlir::success();
1461 auto &block = body.front();
1462 for (mlir::Operation &op : block) {
1465 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1466 circt::moore::ClassMethodDeclOp>(&op))
1469 return emitOpError()
1470 <<
"body may only contain 'moore.class.propertydecl' operations";
1472 return mlir::success();
1475LogicalResult ClassNewOp::verify() {
1478 auto handleTy = cast<ClassHandleType>(getResult().getType());
1479 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1481 return emitOpError(
"result type is missing a class symbol");
1484 mlir::Operation *sym =
1485 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1487 return emitOpError(
"referenced class symbol `")
1488 << classSym <<
"` was not found";
1490 if (!llvm::isa<ClassDeclOp>(sym))
1491 return emitOpError(
"symbol `")
1492 << classSym <<
"` does not name a `moore.class.classdecl`";
1494 return mlir::success();
1497void ClassNewOp::getEffects(
1498 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1501 effects.emplace_back(MemoryEffects::Allocate::get());
1505ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1507 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1509 return emitOpError() <<
"operand must be !moore.class<...>; got "
1510 << getOperand().getType();
1512 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1514 return emitOpError() <<
"result must be !moore.class<...>; got "
1515 << getResult().getType();
1520 auto *op = getOperation();
1523 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1525 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1526 if (!srcDeclOp || !dstDeclOp)
1527 return emitOpError() <<
"failed to resolve class symbol(s): src="
1528 << srcTy.getClassSym()
1529 <<
", dst=" << dstTy.getClassSym();
1531 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1532 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1533 if (!srcDecl || !dstDecl)
1534 return emitOpError()
1535 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1536 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1543 auto baseSym = cur.getBaseAttr();
1547 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1548 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1551 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1552 << dstTy.getClassSym()
1553 <<
" (destination is not a base class)";
1557ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1559 Type instTy = getInstance().getType();
1560 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1562 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1566 SymbolRefAttr classSym = handleTy.getClassSym();
1568 return emitOpError(
"instance type is missing a class symbol");
1572 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1574 return emitOpError(
"referenced class symbol `")
1575 << classSym <<
"` was not found";
1576 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1578 return emitOpError(
"symbol `")
1579 << classSym <<
"` does not name a `moore.class.classdecl`";
1582 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1584 return emitOpError(
"missing field symbol");
1586 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1588 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1590 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1592 return emitOpError(
"symbol `")
1593 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1596 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1598 return emitOpError(
"result must be a !moore.ref<T>");
1600 Type expectedElemTy = fieldDecl.getPropertyType();
1601 if (resRefTy.getNestedType() != expectedElemTy)
1602 return emitOpError(
"result element type (")
1603 << resRefTy.getNestedType() <<
") does not match field type ("
1604 << expectedElemTy <<
")";
1610VTableLoadMethodOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1611 Operation *op = getOperation();
1613 auto object = getObject();
1614 auto implSym =
object.getType().getClassSym();
1617 Operation *implOp = symbolTable.lookupNearestSymbolFrom(op, implSym);
1619 return emitOpError() <<
"implementing class " << implSym <<
" not found";
1620 auto implClass = cast<moore::ClassDeclOp>(implOp);
1622 StringAttr methodName = getMethodSymAttr().getLeafReference();
1623 if (!methodName || methodName.getValue().empty())
1624 return emitOpError() <<
"empty method name";
1626 moore::ClassDeclOp cursor = implClass;
1627 Operation *methodDeclOp =
nullptr;
1630 while (cursor && !methodDeclOp) {
1631 methodDeclOp = symbolTable.lookupSymbolIn(cursor, methodName);
1634 SymbolRefAttr baseSym = cursor.getBaseAttr();
1637 Operation *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1638 cursor = baseOp ? cast<moore::ClassDeclOp>(baseOp) : moore::ClassDeclOp();
1642 return emitOpError() <<
"no method `" << methodName <<
"` found in "
1643 << implClass.getSymName() <<
" or its bases";
1646 auto methodDecl = dyn_cast<moore::ClassMethodDeclOp>(methodDeclOp);
1648 return emitOpError() <<
"`" << methodName
1649 <<
"` is not a method declaration";
1652 auto resFnTy = cast<FunctionType>(getResult().getType());
1653 auto declFnTy = cast<FunctionType>(methodDecl.getFunctionType());
1654 if (resFnTy != declFnTy)
1655 return emitOpError() <<
"result type " << resFnTy
1656 <<
" does not match method erased ABI " << declFnTy;
1661LogicalResult VTableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1662 Operation *self = getOperation();
1665 SymbolRefAttr name = getSymNameAttr();
1667 return emitOpError(
"requires 'sym_name' SymbolRefAttr");
1670 Operation *rootDef = symbolTable.lookupNearestSymbolFrom(
1671 self, SymbolRefAttr::get(name.getRootReference()));
1673 return emitOpError() <<
"cannot resolve root class symbol '"
1674 << name.getRootReference() <<
"' for sym_name "
1677 if (!isa<ClassDeclOp>(rootDef))
1678 return emitOpError()
1679 <<
"root of sym_name must name a 'moore.class.classdecl', got "
1686LogicalResult VTableOp::verifyRegions() {
1688 for (Operation &op : getBody().front()) {
1689 if (!isa<VTableOp, VTableEntryOp>(op))
1691 "body may only contain 'moore.vtable' or 'moore.vtable_entry' ops");
1693 return mlir::success();
1697VTableEntryOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1698 Operation *self = getOperation();
1702 SymbolRefAttr target = getTargetAttr();
1704 symbolTable.lookupNearestSymbolFrom<func::FuncOp>(self, target);
1706 return emitOpError()
1707 <<
"cannot resolve target symbol to a function operation " << target;
1710 if (!isa<VTableOp>(self->getParentOp()))
1711 return emitOpError(
"must be nested directly inside a 'moore.vtable' op");
1713 Operation *currentOp = self;
1714 VTableOp currentVTable;
1715 bool defined =
false;
1722 while (
auto parentOp = dyn_cast<VTableOp>(currentOp->getParentOp())) {
1723 currentOp = parentOp;
1724 currentVTable = cast<VTableOp>(currentOp);
1726 auto classSymName = currentVTable.getSymName();
1727 ClassDeclOp parentClassDecl =
1728 symbolTable.lookupNearestSymbolFrom<ClassDeclOp>(
1729 parentOp, classSymName.getRootReference());
1730 assert(parentClassDecl &&
"VTableOp must point to a classdeclop");
1732 for (
auto method : parentClassDecl.getBody().getOps<ClassMethodDeclOp>()) {
1734 if (!method.getImpl())
1738 if (method.getSymName() ==
getName() && method.getImplAttr() == target)
1746 else if (method.getSymName() ==
getName() &&
1747 method.getImplAttr() != target && defined)
1748 return emitOpError() <<
"Target " << target
1749 <<
" should be overridden by " << classSymName;
1753 return emitOpError()
1754 <<
"Parent class does not point to any implementation!";
1764#define GET_OP_CLASSES
1765#include "circt/Dialect/Moore/Moore.cpp.inc"
1766#include "circt/Dialect/Moore/MooreEnums.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static Location getLoc(DefSlot slot)
static OpFoldResult powCommonFolding(MLIRContext *ctxt, Attribute lhs, Attribute rhs)
static ArrayRef< StructLikeMember > getStructMembers(Type type)
static std::optional< uint32_t > getStructFieldIndex(Type type, StringAttr name)
static UnpackedType getStructFieldType(Type type, StringAttr name)
static std::pair< unsigned, UnpackedType > getArrayElements(Type type)
static InstancePath empty
Four-valued arbitrary precision integers.
bool isNegative() const
Determine whether the integer interpreted as a signed number would be negative.
FVInt sext(unsigned bitWidth) const
Sign-extend the integer to a new bit width.
unsigned getSignificantBits() const
Compute the minimum bit width necessary to accurately represent this integer's value and sign.
static FVInt getAllX(unsigned numBits)
Construct an FVInt with all bits set to X.
bool hasUnknown() const
Determine if any bits are X or Z.
unsigned getActiveBits() const
Compute the number of active bits in the value.
unsigned getBitWidth() const
Return the number of bits this integer has.
FVInt trunc(unsigned bitWidth) const
Truncate the integer to a smaller bit width.
A packed SystemVerilog type.
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Domain getDomain() const
Get the value domain of this type.
An unpacked SystemVerilog type.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction
The direction of a Component or Cell port.
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
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)
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function type.
Domain
The number of values each bit of a type can assume.
RealWidth
The type of floating point / real number behind a RealType.
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.
void printFVInt(AsmPrinter &p, const FVInt &value)
Print a four-valued integer usign an AsmPrinter.
ParseResult parseFVInt(AsmParser &p, FVInt &result)
Parse a four-valued integer using an AsmParser.
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