18#include "mlir/IR/Builders.h"
19#include "mlir/Interfaces/FunctionImplementation.h"
20#include "llvm/ADT/APSInt.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include <mlir/Dialect/Func/IR/FuncOps.h>
33void SVModuleOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
34 llvm::StringRef name, hw::ModuleType type) {
35 state.addAttribute(SVModuleOp::getSymNameAttrName(state.name),
36 builder.getStringAttr(name));
37 state.addAttribute(getModuleTypeAttrName(state.name), TypeAttr::get(type));
41void SVModuleOp::print(OpAsmPrinter &p) {
45 StringRef visibilityAttrName =
46 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
47 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
48 p << visibility.getValue() <<
' ';
50 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
53 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
56 p.printRegion(getBodyRegion(),
false,
60ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
62 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
66 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
71 SmallVector<hw::module_like_impl::PortParse> ports;
76 result.addAttribute(getModuleTypeAttrName(result.name), modType);
79 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
83 SmallVector<OpAsmParser::Argument, 4> entryArgs;
84 for (
auto &port : ports)
86 entryArgs.push_back(port);
89 auto &bodyRegion = *result.addRegion();
90 if (parser.parseRegion(bodyRegion, entryArgs))
93 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
97void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
99 if (®ion != &getBodyRegion())
102 for (
auto [index, arg] : llvm::enumerate(region.front().getArguments()))
103 setNameFn(arg, moduleType.getInputNameAttr(index));
106OutputOp SVModuleOp::getOutputOp() {
107 return cast<OutputOp>(getBody()->getTerminator());
110OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
116LogicalResult OutputOp::verify() {
117 auto module = getParentOp();
120 auto outputTypes =
module.getModuleType().getOutputTypes();
121 if (outputTypes.size() != getNumOperands())
122 return emitOpError(
"has ")
123 << getNumOperands() <<
" operands, but enclosing module @"
124 <<
module.getSymName() << " has " << outputTypes.size()
128 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
129 if (outputTypes[i] != getOperand(i).getType())
130 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
131 <<
") does not match output type (" << outputTypes[i]
132 <<
") of module @" << module.getSymName();
141LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
144 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
146 return emitOpError(
"references unknown symbol @") << getModuleName();
149 auto module = dyn_cast<SVModuleOp>(symbol);
151 return emitOpError(
"must reference a 'moore.module', but @")
152 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
155 auto moduleType =
module.getModuleType();
156 auto inputTypes = moduleType.getInputTypes();
158 if (inputTypes.size() != getNumOperands())
159 return emitOpError(
"has ")
160 << getNumOperands() <<
" operands, but target module @"
161 <<
module.getSymName() << " has " << inputTypes.size() << " inputs";
163 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
164 if (inputTypes[i] != getOperand(i).getType())
165 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
166 <<
") does not match input type (" << inputTypes[i]
167 <<
") of module @" << module.getSymName();
170 auto outputTypes = moduleType.getOutputTypes();
172 if (outputTypes.size() != getNumResults())
173 return emitOpError(
"has ")
174 << getNumOperands() <<
" results, but target module @"
175 <<
module.getSymName() << " has " << outputTypes.size()
178 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
179 if (outputTypes[i] != getResult(i).getType())
180 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
181 <<
") does not match output type (" << outputTypes[i]
182 <<
") of module @" << module.getSymName();
187void InstanceOp::print(OpAsmPrinter &p) {
189 p.printAttributeWithoutType(getInstanceNameAttr());
191 p.printAttributeWithoutType(getModuleNameAttr());
197 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
200ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
202 StringAttr instanceName;
203 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
207 FlatSymbolRefAttr moduleName;
208 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
212 auto loc = parser.getCurrentLocation();
213 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
214 SmallVector<Type> types;
218 if (parser.resolveOperands(inputs, types, loc, result.operands))
220 result.addAttribute(
"inputNames", names);
223 if (parser.parseArrow())
230 result.addAttribute(
"outputNames", names);
231 result.addTypes(types);
234 if (parser.parseOptionalAttrDict(result.attributes))
241 SmallString<32> name;
244 auto baseLen = name.size();
246 for (
auto [result, portName] :
247 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
248 if (!portName || portName.empty())
250 name.resize(baseLen);
251 name += portName.getValue();
252 setNameFn(result, name);
260ParseResult CoroutineOp::parse(OpAsmParser &parser, OperationState &result) {
262 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
263 function_interface_impl::VariadicFlag,
264 std::string &) {
return builder.getFunctionType(argTypes, results); };
266 return function_interface_impl::parseFunctionOp(
267 parser, result,
false,
268 getFunctionTypeAttrName(result.name), buildFuncType,
269 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
272void CoroutineOp::print(OpAsmPrinter &p) {
273 function_interface_impl::printFunctionOp(
274 p, *
this,
false, getFunctionTypeAttrName(),
275 getArgAttrsAttrName(), getResAttrsAttrName());
283CallCoroutineOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
284 auto calleeName = getCalleeAttr();
286 symbolTable.lookupNearestSymbolFrom<CoroutineOp>(*
this, calleeName);
288 return emitOpError() <<
"'" << calleeName.getValue()
289 <<
"' does not reference a valid 'moore.coroutine'";
291 auto type = coroutine.getFunctionType();
292 if (type.getNumInputs() != getNumOperands())
293 return emitOpError() <<
"has " << getNumOperands()
294 <<
" operands, but callee expects "
295 << type.getNumInputs();
297 for (
unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
298 if (getOperand(i).getType() != type.getInput(i))
299 return emitOpError() <<
"operand " << i <<
" type mismatch: expected "
300 << type.getInput(i) <<
", got "
301 << getOperand(i).getType();
303 if (type.getNumResults() != getNumResults())
304 return emitOpError() <<
"has " << getNumResults()
305 <<
" results, but callee returns "
306 << type.getNumResults();
308 for (
unsigned i = 0, e = type.getNumResults(); i != e; ++i)
309 if (getResult(i).getType() != type.getResult(i))
310 return emitOpError() <<
"result " << i <<
" type mismatch: expected "
311 << type.getResult(i) <<
", got "
312 << getResult(i).getType();
323 setNameFn(getResult(), *
getName());
326LogicalResult VariableOp::canonicalize(VariableOp op,
327 PatternRewriter &rewriter) {
331 auto initial = op.getInitial();
332 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
333 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
334 rewriter.setInsertionPointAfter(op);
335 BlockingAssignOp::create(rewriter, initial.getLoc(), op, initial);
342 auto *block = op->getBlock();
343 ContinuousAssignOp uniqueAssignOp;
344 for (
auto *user : op->getUsers()) {
346 if (user->getBlock() != block)
350 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
353 uniqueAssignOp = assignOp;
358 if (!isa<ReadOp>(user))
366 Value assignedValue = uniqueAssignOp.getSrc();
367 if (
auto name = op.getNameAttr(); name && !name.empty())
368 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
369 uniqueAssignOp.getSrc());
372 rewriter.eraseOp(uniqueAssignOp);
373 for (
auto *user : llvm::make_early_inc_range(op->getUsers())) {
374 auto readOp = cast<ReadOp>(user);
375 rewriter.replaceOp(readOp, assignedValue);
379 rewriter.eraseOp(op);
383SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
386 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
392 auto nestedType = dyn_cast<PackedType>(getType().getNestedType());
393 if (!nestedType || !nestedType.getBitSize())
396 return {MemorySlot{getResult(), getType().getNestedType()}};
399Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
400 auto packedType = dyn_cast<PackedType>(slot.valueType);
403 auto bitWidth = packedType.getBitSize();
408 : FVInt::getZero(*bitWidth);
409 Value value = ConstantOp::create(
411 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
412 if (value.getType() != packedType)
413 value = SBVToPackedOp::create(builder,
getLoc(), packedType, value);
417void VariableOp::handleBlockArgument(
const MemorySlot &slot,
418 BlockArgument argument,
419 OpBuilder &builder) {}
421std::optional<mlir::PromotableAllocationOpInterface>
422VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
423 OpBuilder &builder) {
424 if (defaultValue && defaultValue.use_empty())
425 defaultValue.getDefiningOp()->erase();
430SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
431 if (isa<SVModuleOp>(getOperation()->getParentOp()))
436 auto refType = getType();
437 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
441 auto destructuredType = destructurable.getSubelementIndexMap();
442 if (!destructuredType)
445 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
448DenseMap<Attribute, MemorySlot> VariableOp::destructure(
449 const DestructurableMemorySlot &slot,
450 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
451 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
452 assert(slot.ptr == getResult());
454 builder.setInsertionPointAfter(*
this);
456 auto destructurableType = cast<DestructurableTypeInterface>(getType());
457 DenseMap<Attribute, MemorySlot> slotMap;
458 for (Attribute index : usedIndices) {
459 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
460 assert(elemType &&
"used index must exist");
462 if (
auto name =
getName(); name && !name->empty())
463 varName = StringAttr::get(
464 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
466 VariableOp::create(builder,
getLoc(), elemType, varName, Value());
467 newAllocators.push_back(varOp);
468 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
474std::optional<DestructurableAllocationOpInterface>
475VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
476 OpBuilder &builder) {
477 assert(slot.ptr == getResult());
488 setNameFn(getResult(), *
getName());
491LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
492 bool modified =
false;
496 auto *block = op->getBlock();
497 ContinuousAssignOp uniqueAssignOp;
498 bool allUsesAreReads =
true;
499 for (
auto *user : op->getUsers()) {
501 if (user->getBlock() != block)
505 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
508 uniqueAssignOp = assignOp;
513 if (!isa<ReadOp>(user))
514 allUsesAreReads =
false;
519 if (uniqueAssignOp && !op.getAssignment()) {
520 rewriter.modifyOpInPlace(
521 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
522 rewriter.eraseOp(uniqueAssignOp);
530 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
533 auto assignedValue = op.getAssignment();
534 if (
auto name = op.getNameAttr(); name && !name.empty())
535 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
540 for (
auto *user : llvm::make_early_inc_range(op->getUsers())) {
541 auto readOp = cast<ReadOp>(user);
542 rewriter.replaceOp(readOp, assignedValue);
544 rewriter.eraseOp(op);
557 setNameFn(getResult(), *
getName());
560LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
561 PatternRewriter &rewriter) {
564 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
565 if (otherOp != op && otherOp.getNameAttr() == op.getNameAttr()) {
566 rewriter.replaceOp(op, otherOp);
572 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
574 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
575 auto moduleType = moduleOp.getModuleType();
576 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
577 if (portName == op.getNameAttr()) {
578 rewriter.replaceOp(op, blockArg);
585 for (
auto &use : op->getUses()) {
586 auto *useOwner = use.getOwner();
587 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
588 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
589 auto moduleType = moduleOp.getModuleType();
590 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
591 if (portName == op.getNameAttr()) {
592 rewriter.replaceOp(op, op.getInput());
607LogicalResult GlobalVariableOp::verifyRegions() {
608 if (
auto *block = getInitBlock()) {
609 auto &terminator = block->back();
610 if (!isa<YieldOp>(terminator))
611 return emitOpError() <<
"must have a 'moore.yield' terminator";
616Block *GlobalVariableOp::getInitBlock() {
617 if (getInitRegion().
empty())
619 return &getInitRegion().front();
627GetGlobalVariableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
630 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
632 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
635 auto var = dyn_cast<GlobalVariableOp>(symbol);
637 return emitOpError() <<
"must reference a 'moore.global_variable', but "
638 << getGlobalNameAttr() <<
" is a '"
639 << symbol->getName() <<
"'";
642 auto expType = var.getType();
643 auto actType = getType().getNestedType();
644 if (expType != actType)
645 return emitOpError() <<
"returns a " << actType <<
" reference, but "
646 << getGlobalNameAttr() <<
" is of type " << expType;
655void ConstantOp::print(OpAsmPrinter &p) {
658 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
660 p.printStrippedAttrOrType(getType());
663ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
666 auto valueLoc = parser.getCurrentLocation();
671 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
676 if (parser.parseCustomTypeWithFallback(type))
684 value = value.
sext(type.getWidth());
685 }
else if (type.getWidth() < value.
getBitWidth()) {
688 unsigned neededBits =
690 if (type.getWidth() < neededBits)
691 return parser.emitError(valueLoc)
692 <<
"value requires " << neededBits
693 <<
" bits, but result type only has " << type.getWidth();
694 value = value.
trunc(type.getWidth());
700 return parser.emitError(valueLoc)
701 <<
"value contains X or Z bits, but result type " << type
702 <<
" only allows two-valued bits";
705 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
706 result.addAttribute(
"value", attrValue);
707 result.addTypes(type);
711LogicalResult ConstantOp::verify() {
712 auto attrWidth = getValue().getBitWidth();
713 auto typeWidth = getType().getWidth();
714 if (attrWidth != typeWidth)
715 return emitError(
"attribute width ")
716 << attrWidth <<
" does not match return type's width " << typeWidth;
720void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
721 const FVInt &value) {
723 "FVInt width must match type width");
724 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
727void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
728 const APInt &value) {
729 assert(type.getWidth() == value.getBitWidth() &&
730 "APInt width must match type width");
731 build(builder, result, type, FVInt(value));
738void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
739 int64_t value,
bool isSigned) {
740 build(builder, result, type,
741 APInt(type.getWidth(), (uint64_t)value, isSigned));
745void ConstantOp::build(OpBuilder &builder, OperationState &result,
746 Domain domain,
bool value) {
747 auto type = IntType::get(builder.getContext(), 1, domain);
748 build(builder, result, type, value ? 1 : 0,
false);
751OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
752 assert(adaptor.getOperands().empty() &&
"constant has no operands");
753 return getValueAttr();
760OpFoldResult ConstantTimeOp::fold(FoldAdaptor adaptor) {
761 return getValueAttr();
768LogicalResult ConstantRealOp::inferReturnTypes(
769 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
770 DictionaryAttr
attrs, mlir::PropertyRef properties,
771 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
772 ConstantRealOp::Adaptor adaptor(operands,
attrs, properties);
773 results.push_back(RealType::get(
775 adaptor.getValueAttr().getType().getIntOrFloatBitWidth())));
783LogicalResult ConcatOp::inferReturnTypes(
784 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
785 DictionaryAttr
attrs, mlir::PropertyRef properties,
786 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
789 for (
auto operand : operands) {
790 auto type = cast<IntType>(operand.getType());
793 width += type.getWidth();
795 results.push_back(IntType::get(
context, width, domain));
803LogicalResult ConcatRefOp::inferReturnTypes(
804 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
805 DictionaryAttr
attrs, mlir::PropertyRef properties,
806 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
807 if (operands.empty())
808 return emitOptionalError(loc,
"requires at least one operand");
811 for (Value operand : operands) {
812 if (operand.getType().getTypeID() != operands[0].getType().getTypeID())
813 return emitOptionalError(loc,
"operands must all be refs or all be nets");
815 cast<WrapperType>(operand.getType()).getNestedType();
816 PackedType packedType = dyn_cast<PackedType>(nestedType);
826 std::optional<int> bitSize = packedType.
getBitSize();
832 results.push_back(cast<WrapperType>(operands[0].getType())
833 .withNestedType(IntType::get(
context, width, domain)));
842 if (
auto arrayType = dyn_cast<ArrayType>(type))
843 return {arrayType.getSize(), arrayType.getElementType()};
844 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
845 return {arrayType.getSize(), arrayType.getElementType()};
846 assert(0 &&
"expected ArrayType or UnpackedArrayType");
850LogicalResult ArrayCreateOp::verify() {
854 if (getElements().size() != size)
855 return emitOpError() <<
"has " << getElements().size()
856 <<
" operands, but result type requires " << size;
862 auto value = getElements()[0];
864 return emitOpError() <<
"operands have type " << value.getType()
875 if (
auto structType = dyn_cast<StructType>(type))
876 return structType.getFieldIndex(name);
877 if (
auto structType = dyn_cast<UnpackedStructType>(type))
878 return structType.getFieldIndex(name);
879 assert(0 &&
"expected StructType or UnpackedStructType");
884 if (
auto structType = dyn_cast<StructType>(type))
885 return structType.getMembers();
886 if (
auto structType = dyn_cast<UnpackedStructType>(type))
887 return structType.getMembers();
888 assert(0 &&
"expected StructType or UnpackedStructType");
898LogicalResult StructCreateOp::verify() {
902 if (getFields().size() != members.size())
903 return emitOpError() <<
"has " << getFields().size()
904 <<
" operands, but result type requires "
908 for (
auto [index, pair] : llvm::enumerate(llvm::zip(getFields(), members))) {
909 auto [value, member] = pair;
910 if (value.getType() != member.type)
911 return emitOpError() <<
"operand #" << index <<
" has type "
912 << value.getType() <<
", but struct field "
913 << member.name <<
" requires " << member.type;
918OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
919 SmallVector<NamedAttribute> fields;
920 for (
auto [member, field] :
924 fields.push_back(NamedAttribute(member.name, field));
926 return DictionaryAttr::get(getContext(), fields);
933LogicalResult StructExtractOp::verify() {
936 return emitOpError() <<
"extracts field " << getFieldNameAttr()
937 <<
" which does not exist in " << getInput().getType();
938 if (type != getType())
939 return emitOpError() <<
"result type " << getType()
940 <<
" must match struct field type " << type;
944OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
946 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
947 if (
auto value = fields.get(getFieldNameAttr()))
951 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
952 if (inject.getFieldNameAttr() == getFieldNameAttr())
953 return inject.getNewValue();
958 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
960 return create.getFields()[*index];
971LogicalResult StructExtractRefOp::verify() {
973 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
975 return emitOpError() <<
"extracts field " << getFieldNameAttr()
976 <<
" which does not exist in " << getInput().getType();
977 if (type != getType().getNestedType())
978 return emitOpError() <<
"result ref of type " << getType().getNestedType()
979 <<
" must match struct field type " << type;
983bool StructExtractRefOp::canRewire(
984 const DestructurableMemorySlot &slot,
985 SmallPtrSetImpl<Attribute> &usedIndices,
986 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
987 const DataLayout &dataLayout) {
988 if (slot.ptr != getInput())
990 auto index = getFieldNameAttr();
991 if (!index || !slot.subelementTypes.contains(index))
993 usedIndices.insert(index);
998StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
999 DenseMap<Attribute, MemorySlot> &subslots,
1000 OpBuilder &builder,
const DataLayout &dataLayout) {
1001 auto index = getFieldNameAttr();
1002 const MemorySlot &memorySlot = subslots.at(index);
1003 replaceAllUsesWith(memorySlot.ptr);
1004 getInputMutable().drop();
1006 return DeletionKind::Keep;
1013LogicalResult StructInjectOp::verify() {
1016 return emitOpError() <<
"injects field " << getFieldNameAttr()
1017 <<
" which does not exist in " << getInput().getType();
1018 if (type != getNewValue().getType())
1019 return emitOpError() <<
"injected value " << getNewValue().getType()
1020 <<
" must match struct field type " << type;
1024OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
1025 auto input = adaptor.getInput();
1026 auto newValue = adaptor.getNewValue();
1027 if (!input || !newValue)
1029 NamedAttrList fields(cast<DictionaryAttr>(input));
1030 fields.set(getFieldNameAttr(), newValue);
1031 return fields.getDictionary(getContext());
1034LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
1035 PatternRewriter &rewriter) {
1040 SmallPtrSet<Operation *, 4> injectOps;
1041 DenseMap<StringAttr, Value> fieldValues;
1043 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
1044 if (!injectOps.insert(injectOp).second)
1046 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
1047 input = injectOp.getInput();
1049 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
1050 for (
auto [value, member] : llvm::zip(createOp.getFields(), members))
1051 fieldValues.insert({member.name, value});
1054 if (fieldValues.size() == members.size()) {
1055 SmallVector<Value> values;
1056 values.reserve(fieldValues.size());
1057 for (
auto member : members)
1058 values.push_back(fieldValues.lookup(member.name));
1059 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
1065 if (injectOps.size() == fieldValues.size())
1070 for (
auto member : members)
1071 if (
auto value = fieldValues.lookup(member.name))
1072 input = StructInjectOp::create(rewriter, op.getLoc(), op.getType(), input,
1073 member.name, value);
1074 rewriter.replaceOp(op, input);
1082LogicalResult UnionCreateOp::verify() {
1085 return TypeSwitch<Type, LogicalResult>(getType())
1086 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1087 auto members = type.getMembers();
1088 auto inputType = getInput().getType();
1090 for (
const auto &member : members)
1091 if (member.name == fieldName && member.type == inputType)
1093 for (
const auto &member : members) {
1094 if (member.name == fieldName) {
1095 emitOpError() <<
"input type " << inputType
1096 <<
" does not match union field '" << fieldName
1097 <<
"' type " << member.type;
1101 emitOpError() <<
"field '" << fieldName <<
"' not found in union type";
1104 .Default([
this](
auto &) {
1105 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1114LogicalResult UnionExtractOp::verify() {
1117 return TypeSwitch<Type, LogicalResult>(getInput().getType())
1118 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1119 auto members = type.getMembers();
1121 auto resultType = getType();
1122 for (
const auto &member : members)
1123 if (member.name == fieldName && member.type == resultType)
1125 emitOpError(
"result type must match the union field type");
1128 .Default([
this](
auto &) {
1129 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1138LogicalResult UnionExtractRefOp::verify() {
1141 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1142 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1143 auto members = type.getMembers();
1145 auto resultType = getType().getNestedType();
1146 for (
const auto &member : members)
1147 if (member.name == fieldName && member.type == resultType)
1149 emitOpError(
"result type must match the union field type");
1152 .Default([
this](
auto &) {
1153 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1162LogicalResult YieldOp::verify() {
1164 auto *parentOp = getOperation()->getParentOp();
1165 if (
auto cond = dyn_cast<ConditionalOp>(parentOp)) {
1166 expType = cond.getType();
1167 }
else if (
auto varOp = dyn_cast<GlobalVariableOp>(parentOp)) {
1168 expType = varOp.getType();
1170 llvm_unreachable(
"all in ParentOneOf handled");
1173 auto actType = getOperand().getType();
1174 if (expType != actType) {
1175 return emitOpError() <<
"yields " << actType <<
", but parent expects "
1185OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1187 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1188 return reverseOp.getInput();
1192 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1193 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1202OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1207 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1217OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1219 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1220 return reverseOp.getInput();
1223 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1224 return FVIntegerAttr::get(getContext(), attr.getValue());
1233OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1235 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1236 return reverseOp.getInput();
1239 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1240 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1250OpFoldResult ConvertRealOp::fold(FoldAdaptor adaptor) {
1251 if (getInput().getType() == getResult().getType())
1261OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1263 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1264 auto width = getType().getWidth();
1265 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1275OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1277 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1278 auto width = getType().getWidth();
1279 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1289OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1291 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1292 auto width = getType().getWidth();
1293 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1303OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1305 if (getInput().getType() == getResult().getType())
1314bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1316bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1317 return getDst() == slot.ptr;
1320Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1322 const DataLayout &dataLayout) {
1326bool BlockingAssignOp::canUsesBeRemoved(
1327 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1328 SmallVectorImpl<OpOperand *> &newBlockingUses,
1329 const DataLayout &dataLayout) {
1331 if (blockingUses.size() != 1)
1333 Value blockingUse = (*blockingUses.begin())->get();
1334 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1335 getSrc() != slot.ptr && getSrc().getType() == slot.valueType;
1338DeletionKind BlockingAssignOp::removeBlockingUses(
1339 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1340 OpBuilder &builder, Value reachingDefinition,
1341 const DataLayout &dataLayout) {
1342 return DeletionKind::Delete;
1349bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1350 return getInput() == slot.ptr;
1353bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1355Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1356 Value reachingDef,
const DataLayout &dataLayout) {
1357 llvm_unreachable(
"getStored should not be called on ReadOp");
1360bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1361 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1362 SmallVectorImpl<OpOperand *> &newBlockingUses,
1363 const DataLayout &dataLayout) {
1365 if (blockingUses.size() != 1)
1367 Value blockingUse = (*blockingUses.begin())->get();
1368 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1369 getResult().getType() == slot.valueType;
1373ReadOp::removeBlockingUses(
const MemorySlot &slot,
1374 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1375 OpBuilder &builder, Value reachingDefinition,
1376 const DataLayout &dataLayout) {
1377 getResult().replaceAllUsesWith(reachingDefinition);
1378 return DeletionKind::Delete;
1387 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1388 if (lhsValue && lhsValue.getValue() == 1)
1391 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1392 if (rhsValue && rhsValue.getValue().isZero())
1393 return FVIntegerAttr::get(ctxt,
1394 FVInt(rhsValue.getValue().getBitWidth(), 1));
1399OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1403LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1404 Location loc = op.getLoc();
1405 auto intType = cast<IntType>(op.getRhs().getType());
1406 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1407 if (baseOp.getValue() == 2) {
1408 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1409 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1410 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1411 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1412 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1413 op, op.getLhs().getType(), isNegative);
1414 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1415 rewriter.setInsertionPointToStart(thenBlock);
1416 YieldOp::create(rewriter, loc, constZero);
1417 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1418 rewriter.setInsertionPointToStart(elseBlock);
1419 YieldOp::create(rewriter, loc, shift);
1431OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1435LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1436 Location loc = op.getLoc();
1437 auto intType = cast<IntType>(op.getRhs().getType());
1438 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1439 if (baseOp.getValue() == 2) {
1440 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1441 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1453OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1454 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1455 if (intAttr.getValue().isZero())
1465OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1466 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1467 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1469 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1477OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1478 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1479 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1481 return FVIntegerAttr::get(getContext(),
1482 lhs.getValue().udiv(rhs.getValue()));
1490OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1491 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1492 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1494 return FVIntegerAttr::get(getContext(),
1495 lhs.getValue().sdiv(rhs.getValue()));
1503LogicalResult ClassDeclOp::verify() {
1504 mlir::Region &body = getBody();
1506 return mlir::success();
1508 auto &block = body.front();
1509 for (mlir::Operation &op : block) {
1512 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1513 circt::moore::ClassMethodDeclOp>(&op))
1516 return emitOpError()
1517 <<
"body may only contain 'moore.class.propertydecl' operations";
1519 return mlir::success();
1522LogicalResult ClassNewOp::verify() {
1525 auto handleTy = cast<ClassHandleType>(getResult().getType());
1526 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1528 return emitOpError(
"result type is missing a class symbol");
1531 mlir::Operation *sym =
1532 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1534 return emitOpError(
"referenced class symbol `")
1535 << classSym <<
"` was not found";
1537 if (!llvm::isa<ClassDeclOp>(sym))
1538 return emitOpError(
"symbol `")
1539 << classSym <<
"` does not name a `moore.class.classdecl`";
1541 return mlir::success();
1544void ClassNewOp::getEffects(
1545 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1548 effects.emplace_back(MemoryEffects::Allocate::get());
1552ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1554 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1556 return emitOpError() <<
"operand must be !moore.class<...>; got "
1557 << getOperand().getType();
1559 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1561 return emitOpError() <<
"result must be !moore.class<...>; got "
1562 << getResult().getType();
1567 auto *op = getOperation();
1570 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1572 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1573 if (!srcDeclOp || !dstDeclOp)
1574 return emitOpError() <<
"failed to resolve class symbol(s): src="
1575 << srcTy.getClassSym()
1576 <<
", dst=" << dstTy.getClassSym();
1578 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1579 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1580 if (!srcDecl || !dstDecl)
1581 return emitOpError()
1582 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1583 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1590 auto baseSym = cur.getBaseAttr();
1594 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1595 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1598 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1599 << dstTy.getClassSym()
1600 <<
" (destination is not a base class)";
1604ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1606 Type instTy = getInstance().getType();
1607 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1609 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1613 SymbolRefAttr classSym = handleTy.getClassSym();
1615 return emitOpError(
"instance type is missing a class symbol");
1619 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1621 return emitOpError(
"referenced class symbol `")
1622 << classSym <<
"` was not found";
1623 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1625 return emitOpError(
"symbol `")
1626 << classSym <<
"` does not name a `moore.class.classdecl`";
1629 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1631 return emitOpError(
"missing field symbol");
1633 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1635 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1637 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1639 return emitOpError(
"symbol `")
1640 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1643 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1645 return emitOpError(
"result must be a !moore.ref<T>");
1647 Type expectedElemTy = fieldDecl.getPropertyType();
1648 if (resRefTy.getNestedType() != expectedElemTy)
1649 return emitOpError(
"result element type (")
1650 << resRefTy.getNestedType() <<
") does not match field type ("
1651 << expectedElemTy <<
")";
1657VTableLoadMethodOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1658 Operation *op = getOperation();
1660 auto object = getObject();
1661 auto implSym =
object.getType().getClassSym();
1664 Operation *implOp = symbolTable.lookupNearestSymbolFrom(op, implSym);
1666 return emitOpError() <<
"implementing class " << implSym <<
" not found";
1667 auto implClass = cast<moore::ClassDeclOp>(implOp);
1669 StringAttr methodName = getMethodSymAttr().getLeafReference();
1670 if (!methodName || methodName.getValue().empty())
1671 return emitOpError() <<
"empty method name";
1673 moore::ClassDeclOp cursor = implClass;
1674 Operation *methodDeclOp =
nullptr;
1677 while (cursor && !methodDeclOp) {
1678 methodDeclOp = symbolTable.lookupSymbolIn(cursor, methodName);
1681 SymbolRefAttr baseSym = cursor.getBaseAttr();
1684 Operation *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1685 cursor = baseOp ? cast<moore::ClassDeclOp>(baseOp) : moore::ClassDeclOp();
1689 return emitOpError() <<
"no method `" << methodName <<
"` found in "
1690 << implClass.getSymName() <<
" or its bases";
1693 auto methodDecl = dyn_cast<moore::ClassMethodDeclOp>(methodDeclOp);
1695 return emitOpError() <<
"`" << methodName
1696 <<
"` is not a method declaration";
1699 auto resFnTy = cast<FunctionType>(getResult().getType());
1700 auto declFnTy = cast<FunctionType>(methodDecl.getFunctionType());
1701 if (resFnTy != declFnTy)
1702 return emitOpError() <<
"result type " << resFnTy
1703 <<
" does not match method erased ABI " << declFnTy;
1708LogicalResult VTableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1709 Operation *self = getOperation();
1712 SymbolRefAttr name = getSymNameAttr();
1714 return emitOpError(
"requires 'sym_name' SymbolRefAttr");
1717 Operation *rootDef = symbolTable.lookupNearestSymbolFrom(
1718 self, SymbolRefAttr::get(name.getRootReference()));
1720 return emitOpError() <<
"cannot resolve root class symbol '"
1721 << name.getRootReference() <<
"' for sym_name "
1724 if (!isa<ClassDeclOp>(rootDef))
1725 return emitOpError()
1726 <<
"root of sym_name must name a 'moore.class.classdecl', got "
1733LogicalResult VTableOp::verifyRegions() {
1735 for (Operation &op : getBody().front()) {
1736 if (!isa<VTableOp, VTableEntryOp>(op))
1738 "body may only contain 'moore.vtable' or 'moore.vtable_entry' ops");
1740 return mlir::success();
1744VTableEntryOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1745 Operation *self = getOperation();
1749 SymbolRefAttr target = getTargetAttr();
1751 symbolTable.lookupNearestSymbolFrom<func::FuncOp>(self, target);
1753 return emitOpError()
1754 <<
"cannot resolve target symbol to a function operation " << target;
1757 if (!isa<VTableOp>(self->getParentOp()))
1758 return emitOpError(
"must be nested directly inside a 'moore.vtable' op");
1760 Operation *currentOp = self;
1761 VTableOp currentVTable;
1762 bool defined =
false;
1769 while (
auto parentOp = dyn_cast<VTableOp>(currentOp->getParentOp())) {
1770 currentOp = parentOp;
1771 currentVTable = cast<VTableOp>(currentOp);
1773 auto classSymName = currentVTable.getSymName();
1774 ClassDeclOp parentClassDecl =
1775 symbolTable.lookupNearestSymbolFrom<ClassDeclOp>(
1776 parentOp, classSymName.getRootReference());
1777 assert(parentClassDecl &&
"VTableOp must point to a classdeclop");
1779 for (
auto method : parentClassDecl.getBody().getOps<ClassMethodDeclOp>()) {
1781 if (!method.getImpl())
1785 if (method.getSymName() ==
getName() && method.getImplAttr() == target)
1793 else if (method.getSymName() ==
getName() &&
1794 method.getImplAttr() != target && defined)
1795 return emitOpError() <<
"Target " << target
1796 <<
" should be overridden by " << classSymName;
1800 return emitOpError()
1801 <<
"Parent class does not point to any implementation!";
1806LogicalResult DynQueueExtractOp::verify() {
1807 auto elementType = cast<QueueType>(getInput().getType()).getElementType();
1811 if (getResult().getType() ==
elementType && getLowerIdx() != getUpperIdx()) {
1818LogicalResult QueueResizeOp::verify() {
1819 if (cast<QueueType>(getInput().getType()).getElementType() !=
1820 cast<QueueType>(getResult().getType()).getElementType())
1826LogicalResult QueueFromUnpackedArrayOp::verify() {
1828 auto queueElementType =
1829 cast<QueueType>(getResult().getType()).getElementType();
1831 auto arrayElementType =
1832 cast<UnpackedArrayType>(getInput().getType()).getElementType();
1834 if (queueElementType != arrayElementType) {
1835 return emitOpError()
1836 <<
"Queue element type doesn't match unpacked array element type";
1842LogicalResult QueueConcatOp::verify() {
1846 auto resultElType = cast<QueueType>(getResult().getType()).getElementType();
1848 for (Value input : getInputs()) {
1849 auto inpElType = cast<QueueType>(input.getType()).getElementType();
1850 if (inpElType != resultElType) {
1851 return emitOpError() <<
"Queue element type " << inpElType
1852 <<
" doesn't match result element type "
1860void DPIFuncOp::build(OpBuilder &odsBuilder, OperationState &odsState,
1861 StringAttr symName, ArrayRef<DPIArgInfo> dpiArgs,
1862 ArrayAttr argumentLocs, StringAttr verilogName) {
1863 auto *ctx = odsBuilder.getContext();
1864 odsState.addAttribute(getSymNameAttrName(odsState.name), symName);
1867 SmallVector<Type> inputTypes, resultTypes;
1868 SmallVector<Attribute> dirAttrs, nameAttrs;
1869 for (
auto &arg : dpiArgs) {
1870 dirAttrs.push_back(DPIArgDirectionAttr::get(ctx, arg.dir));
1871 nameAttrs.push_back(arg.name);
1873 inputTypes.push_back(arg.type);
1874 if (arg.dir == DPIArgDirection::Out || arg.dir == DPIArgDirection::InOut ||
1875 arg.dir == DPIArgDirection::Return)
1876 resultTypes.push_back(arg.type);
1879 odsState.addAttribute(
1880 getFunctionTypeAttrName(odsState.name),
1881 TypeAttr::get(FunctionType::get(ctx, inputTypes, resultTypes)));
1882 odsState.addAttribute(getDpiArgDirsAttrName(odsState.name),
1883 odsBuilder.getArrayAttr(dirAttrs));
1884 odsState.addAttribute(getDpiArgNamesAttrName(odsState.name),
1885 odsBuilder.getArrayAttr(nameAttrs));
1888 odsState.addAttribute(getArgumentLocsAttrName(odsState.name), argumentLocs);
1890 odsState.addAttribute(getVerilogNameAttrName(odsState.name), verilogName);
1891 odsState.addRegion();
1896 return llvm::StringSwitch<std::optional<DPIArgDirection>>(keyword)
1897 .Case(
"in", DPIArgDirection::In)
1898 .Case(
"out", DPIArgDirection::Out)
1899 .Case(
"inout", DPIArgDirection::InOut)
1900 .Case(
"return", DPIArgDirection::Return)
1901 .Default(std::nullopt);
1907 case DPIArgDirection::In:
1909 case DPIArgDirection::Out:
1911 case DPIArgDirection::InOut:
1913 case DPIArgDirection::Return:
1916 llvm_unreachable(
"unknown DPIArgDirection");
1919ParseResult DPIFuncOp::parse(OpAsmParser &parser, OperationState &result) {
1920 auto builder = parser.getBuilder();
1921 auto *ctx = builder.getContext();
1923 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1925 StringAttr nameAttr;
1926 if (parser.parseSymbolName(nameAttr,
1927 DPIFuncOp::getSymNameAttrName(result.name),
1931 SmallVector<DPIArgDirection> argDirs;
1932 SmallVector<StringAttr> argNames;
1933 SmallVector<Type> argTypes;
1934 SmallVector<Attribute> argLocs;
1935 auto unknownLoc = builder.getUnknownLoc();
1936 bool hasLocs =
false;
1938 auto parseOneArg = [&]() -> ParseResult {
1939 StringRef dirKeyword;
1940 auto keyLoc = parser.getCurrentLocation();
1941 if (parser.parseKeyword(&dirKeyword))
1945 return parser.emitError(keyLoc,
1946 "expected DPI argument direction keyword");
1949 bool hasSSA = DPIFuncOp::isCallOperandDir(*dir);
1950 std::string argName;
1952 OpAsmParser::UnresolvedOperand ssaName;
1953 if (parser.parseOperand(ssaName,
false))
1955 argName = ssaName.name.substr(1).str();
1957 if (parser.parseKeywordOrString(&argName))
1962 if (parser.parseColonType(argType))
1965 argDirs.push_back(*dir);
1966 argNames.push_back(StringAttr::get(ctx, argName));
1967 argTypes.push_back(argType);
1969 std::optional<Location> maybeLoc;
1970 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1973 argLocs.push_back(*maybeLoc);
1976 argLocs.push_back(unknownLoc);
1981 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOneArg,
1982 " in DPI argument list"))
1986 SmallVector<Type> inputTypes, resultTypes;
1987 for (
auto [dir, type] : llvm::zip(argDirs, argTypes)) {
1988 if (DPIFuncOp::isCallOperandDir(dir))
1989 inputTypes.push_back(type);
1990 if (dir == DPIArgDirection::Out || dir == DPIArgDirection::InOut ||
1991 dir == DPIArgDirection::Return)
1992 resultTypes.push_back(type);
1994 auto funcType = FunctionType::get(ctx, inputTypes, resultTypes);
1995 result.addAttribute(DPIFuncOp::getFunctionTypeAttrName(result.name),
1996 TypeAttr::get(funcType));
1999 SmallVector<Attribute> dirAttrs;
2000 for (
auto d : argDirs)
2001 dirAttrs.push_back(DPIArgDirectionAttr::get(ctx, d));
2002 result.addAttribute(DPIFuncOp::getDpiArgDirsAttrName(result.name),
2003 builder.getArrayAttr(dirAttrs));
2006 SmallVector<Attribute> nameAttrs(argNames.begin(), argNames.end());
2007 result.addAttribute(DPIFuncOp::getDpiArgNamesAttrName(result.name),
2008 builder.getArrayAttr(nameAttrs));
2011 result.addAttribute(DPIFuncOp::getArgumentLocsAttrName(result.name),
2012 builder.getArrayAttr(argLocs));
2015 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2024::mlir::Type DPIFuncOp::cloneTypeWith(::mlir::TypeRange inputs,
2025 ::mlir::TypeRange results) {
2026 return FunctionType::get(getContext(), inputs, results);
2029void DPIFuncOp::getDPIArgTypes(SmallVectorImpl<Type> &argTypes) {
2030 auto funcType = getFunctionType();
2031 auto inputs = funcType.getInputs();
2032 auto results = funcType.getResults();
2033 auto dirs = getDpiArgDirsAttr();
2034 unsigned inputIdx = 0, resultIdx = 0;
2035 for (
auto dirAttr : dirs) {
2036 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2038 case DPIArgDirection::In:
2039 argTypes.push_back(inputs[inputIdx++]);
2041 case DPIArgDirection::Out:
2042 argTypes.push_back(results[resultIdx++]);
2044 case DPIArgDirection::InOut:
2045 argTypes.push_back(inputs[inputIdx++]);
2048 case DPIArgDirection::Return:
2049 argTypes.push_back(results[resultIdx++]);
2055LogicalResult DPIFuncOp::verify() {
2056 auto dirs = getDpiArgDirs();
2057 auto names = getDpiArgNames();
2058 if (dirs.size() != names.size())
2059 return emitOpError(
"argument directions and names must have the same size");
2062 bool seenReturn =
false;
2063 for (
auto [i, dirAttr] : llvm::enumerate(dirs)) {
2064 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2065 if (dir == DPIArgDirection::Return) {
2067 return emitOpError(
"'return' argument must be the last argument");
2068 if (i != dirs.size() - 1)
2069 return emitOpError(
"'return' argument must be the last argument");
2076void DPIFuncOp::print(OpAsmPrinter &p) {
2079 StringRef visibilityAttrName =
2080 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2081 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2082 p << visibility.getValue() <<
' ';
2083 p.printSymbolName(getSymName());
2085 auto dirs = getDpiArgDirs();
2086 auto names = getDpiArgNames();
2087 SmallVector<Type> argTypes;
2088 getDPIArgTypes(argTypes);
2091 llvm::interleaveComma(llvm::enumerate(dirs), p, [&](
auto it) {
2092 auto dir = cast<DPIArgDirectionAttr>(it.value()).getValue();
2093 auto i = it.index();
2094 auto name = cast<StringAttr>(names[i]).getValue();
2095 auto type = argTypes[i];
2101 p.printKeywordOrString(name);
2105 if (getArgumentLocs()) {
2106 auto loc = cast<Location>(getArgumentLocsAttr()[i]);
2107 if (loc != UnknownLoc::get(getContext()))
2108 p.printOptionalLocationSpecifier(loc);
2113 mlir::function_interface_impl::printFunctionAttributes(
2115 {visibilityAttrName, getFunctionTypeAttrName(), getDpiArgDirsAttrName(),
2116 getDpiArgNamesAttrName(), getArgumentLocsAttrName()});
2120FuncDPICallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2121 auto *referencedOp =
2122 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr());
2124 return emitError(
"cannot find function declaration '")
2125 << getCallee() <<
"'";
2126 if (
auto dpiFunc = dyn_cast<DPIFuncOp>(referencedOp)) {
2127 auto funcType = cast<FunctionType>(dpiFunc.getFunctionType());
2128 auto expectedInputs = funcType.getInputs();
2129 auto expectedResults = funcType.getResults();
2130 if (getInputs().size() != expectedInputs.size())
2131 return emitError(
"expects ")
2132 << expectedInputs.size() <<
" DPI operands, but got "
2133 << getInputs().size();
2134 if (getResults().size() != expectedResults.size())
2135 return emitError(
"expects ")
2136 << expectedResults.size() <<
" DPI results, but got "
2137 << getResults().size();
2138 for (
auto [operand, expectedType] : llvm::zip(getInputs(), expectedInputs))
2139 if (operand.getType() != expectedType)
2140 return emitError(
"operand type mismatch: expected ")
2141 << expectedType <<
", but got " << operand.getType();
2142 for (
auto [result, expectedType] : llvm::zip(getResults(), expectedResults))
2143 if (result.getType() != expectedType)
2144 return emitError(
"result type mismatch: expected ")
2145 << expectedType <<
", but got " << result.getType();
2148 if (isa<func::FuncOp>(referencedOp))
2150 return emitError(
"callee must be 'moore.func.dpi' or 'func.func' but got '")
2151 << referencedOp->getName() <<
"'";
2154LogicalResult ReadMemBIOp::verify() {
2155 if (getFinishAddr() && !getStartAddr())
2156 return emitOpError(
"'finishAddr' requires 'startAddr' to be present");
2158 if (getSliceLeft() && !getSliceRight())
2159 return emitOpError(
"'sliceLeft' requires 'sliceRight' to be present");
2160 if (getSliceRight() && !getSliceLeft())
2161 return emitOpError(
"'sliceRight' requires 'sliceLeft' to be present");
2163 auto ref = dyn_cast<moore::RefType>(getDest().getType());
2165 return emitOpError(
"'dest' must be a Moore reference type, got ")
2166 << getDest().getType();
2168 unsigned numDims = 0;
2169 Type nested = ref.getNestedType();
2171 if (isa<moore::QueueType>(nested)) {
2174 while (
auto arr = dyn_cast<moore::UnpackedArrayType>(nested)) {
2176 nested = arr.getElementType();
2181 "'dest' must reference an unpacked array or queue, got ")
2182 << ref.getNestedType();
2184 if (getDimLows().size() != numDims || getDimDescending().size() != numDims)
2185 return emitOpError(
"'dimLows' and 'dimDescending' must have one entry per "
2186 "unpacked dimension");
2196#define GET_OP_CLASSES
2197#include "circt/Dialect/Moore/Moore.cpp.inc"
2198#include "circt/Dialect/Moore/MooreEnums.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static hw::OutputOp getOutputOp(hw::HWModuleOp module)
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static Location getLoc(DefSlot slot)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static std::optional< DPIArgDirection > parseDPIArgDirKeyword(StringRef keyword)
Helper: parse a DPI direction keyword.
static OpFoldResult powCommonFolding(MLIRContext *ctxt, Attribute lhs, Attribute rhs)
static StringRef stringifyDPIArgDir(DPIArgDirection dir)
Helper: stringify a DPI direction.
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.
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.
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
RealWidth
The type of floating point / real number behind a RealType.
bool isCallOperandDir(DPIDirection dir)
True if an argument with this direction is a call operand (input/inout/ref).
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