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(SymbolTable::getSymbolAttrName(),
36 builder.getStringAttr(name));
37 state.addAttribute(getModuleTypeAttrName(state.name), TypeAttr::get(type));
41void SVModuleOp::print(OpAsmPrinter &p) {
45 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
46 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
47 p << visibility.getValue() <<
' ';
49 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
53 p.printRegion(getBodyRegion(),
false,
56 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
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.elemType);
403 auto bitWidth = packedType.getBitSize();
406 auto fvint = packedType.getDomain() == Domain::FourValued
408 :
FVInt::getZero(*bitWidth);
409 Value value = ConstantOp::create(
411 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
412 if (value.getType() != packedType)
413 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);
548 return success(modified);
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());
699 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
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) {
787 Domain domain = Domain::TwoValued;
789 for (
auto operand : operands) {
790 auto type = cast<IntType>(operand.getType());
791 if (type.getDomain() == Domain::FourValued)
792 domain = Domain::FourValued;
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 Domain domain = Domain::TwoValued;
809 for (Value operand : operands) {
810 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
811 PackedType packedType = dyn_cast<PackedType>(nestedType);
817 if (packedType.
getDomain() == Domain::FourValued)
818 domain = Domain::FourValued;
821 std::optional<int> bitSize = packedType.
getBitSize();
827 results.push_back(RefType::get(IntType::get(
context, width, domain)));
836 if (
auto arrayType = dyn_cast<ArrayType>(type))
837 return {arrayType.getSize(), arrayType.getElementType()};
838 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
839 return {arrayType.getSize(), arrayType.getElementType()};
840 assert(0 &&
"expected ArrayType or UnpackedArrayType");
844LogicalResult ArrayCreateOp::verify() {
848 if (getElements().size() != size)
849 return emitOpError() <<
"has " << getElements().size()
850 <<
" operands, but result type requires " << size;
856 auto value = getElements()[0];
858 return emitOpError() <<
"operands have type " << value.getType()
869 if (
auto structType = dyn_cast<StructType>(type))
870 return structType.getFieldIndex(name);
871 if (
auto structType = dyn_cast<UnpackedStructType>(type))
872 return structType.getFieldIndex(name);
873 assert(0 &&
"expected StructType or UnpackedStructType");
878 if (
auto structType = dyn_cast<StructType>(type))
879 return structType.getMembers();
880 if (
auto structType = dyn_cast<UnpackedStructType>(type))
881 return structType.getMembers();
882 assert(0 &&
"expected StructType or UnpackedStructType");
892LogicalResult StructCreateOp::verify() {
896 if (getFields().size() != members.size())
897 return emitOpError() <<
"has " << getFields().size()
898 <<
" operands, but result type requires "
902 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
903 auto [value, member] = pair;
904 if (value.getType() != member.type)
905 return emitOpError() <<
"operand #" << index <<
" has type "
906 << value.getType() <<
", but struct field "
907 << member.name <<
" requires " << member.type;
912OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
913 SmallVector<NamedAttribute> fields;
914 for (
auto [member, field] :
918 fields.push_back(NamedAttribute(member.name, field));
920 return DictionaryAttr::get(getContext(), fields);
927LogicalResult StructExtractOp::verify() {
930 return emitOpError() <<
"extracts field " << getFieldNameAttr()
931 <<
" which does not exist in " << getInput().getType();
932 if (type != getType())
933 return emitOpError() <<
"result type " << getType()
934 <<
" must match struct field type " << type;
938OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
940 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
941 if (
auto value = fields.get(getFieldNameAttr()))
945 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
946 if (inject.getFieldNameAttr() == getFieldNameAttr())
947 return inject.getNewValue();
952 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
954 return create.getFields()[*index];
965LogicalResult StructExtractRefOp::verify() {
967 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
969 return emitOpError() <<
"extracts field " << getFieldNameAttr()
970 <<
" which does not exist in " << getInput().getType();
971 if (type != getType().getNestedType())
972 return emitOpError() <<
"result ref of type " << getType().getNestedType()
973 <<
" must match struct field type " << type;
977bool StructExtractRefOp::canRewire(
978 const DestructurableMemorySlot &slot,
979 SmallPtrSetImpl<Attribute> &usedIndices,
980 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
981 const DataLayout &dataLayout) {
982 if (slot.ptr != getInput())
984 auto index = getFieldNameAttr();
985 if (!index || !slot.subelementTypes.contains(index))
987 usedIndices.insert(index);
992StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
993 DenseMap<Attribute, MemorySlot> &subslots,
994 OpBuilder &builder,
const DataLayout &dataLayout) {
995 auto index = getFieldNameAttr();
996 const MemorySlot &memorySlot = subslots.at(index);
997 replaceAllUsesWith(memorySlot.ptr);
998 getInputMutable().drop();
1000 return DeletionKind::Keep;
1007LogicalResult StructInjectOp::verify() {
1010 return emitOpError() <<
"injects field " << getFieldNameAttr()
1011 <<
" which does not exist in " << getInput().getType();
1012 if (type != getNewValue().getType())
1013 return emitOpError() <<
"injected value " << getNewValue().getType()
1014 <<
" must match struct field type " << type;
1018OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
1019 auto input = adaptor.getInput();
1020 auto newValue = adaptor.getNewValue();
1021 if (!input || !newValue)
1023 NamedAttrList fields(cast<DictionaryAttr>(input));
1024 fields.set(getFieldNameAttr(), newValue);
1025 return fields.getDictionary(getContext());
1028LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
1029 PatternRewriter &rewriter) {
1034 SmallPtrSet<Operation *, 4> injectOps;
1035 DenseMap<StringAttr, Value> fieldValues;
1037 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
1038 if (!injectOps.insert(injectOp).second)
1040 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
1041 input = injectOp.getInput();
1043 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
1044 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
1045 fieldValues.insert({member.name, value});
1048 if (fieldValues.size() == members.size()) {
1049 SmallVector<Value> values;
1050 values.reserve(fieldValues.size());
1051 for (
auto member : members)
1052 values.push_back(fieldValues.lookup(member.name));
1053 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
1059 if (injectOps.size() == fieldValues.size())
1064 for (
auto member : members)
1065 if (auto value = fieldValues.lookup(member.name))
1066 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
1067 member.name, value);
1068 rewriter.replaceOp(op, input);
1076LogicalResult UnionCreateOp::verify() {
1079 return TypeSwitch<Type, LogicalResult>(getType())
1080 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1081 auto members = type.getMembers();
1082 auto inputType = getInput().getType();
1084 for (
const auto &member : members)
1085 if (member.name == fieldName && member.type == inputType)
1087 for (
const auto &member : members) {
1088 if (member.name == fieldName) {
1089 emitOpError() <<
"input type " << inputType
1090 <<
" does not match union field '" << fieldName
1091 <<
"' type " << member.type;
1095 emitOpError() <<
"field '" << fieldName <<
"' not found in union type";
1098 .Default([
this](
auto &) {
1099 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1108LogicalResult UnionExtractOp::verify() {
1111 return TypeSwitch<Type, LogicalResult>(getInput().getType())
1112 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1113 auto members = type.getMembers();
1115 auto resultType = getType();
1116 for (
const auto &member : members)
1117 if (member.name == fieldName && member.type == resultType)
1119 emitOpError(
"result type must match the union field type");
1122 .Default([
this](
auto &) {
1123 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1132LogicalResult UnionExtractRefOp::verify() {
1135 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1136 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1137 auto members = type.getMembers();
1139 auto resultType = getType().getNestedType();
1140 for (
const auto &member : members)
1141 if (member.name == fieldName && member.type == resultType)
1143 emitOpError(
"result type must match the union field type");
1146 .Default([
this](
auto &) {
1147 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1156LogicalResult YieldOp::verify() {
1158 auto *parentOp = getOperation()->getParentOp();
1159 if (
auto cond = dyn_cast<ConditionalOp>(parentOp)) {
1160 expType = cond.getType();
1161 }
else if (
auto varOp = dyn_cast<GlobalVariableOp>(parentOp)) {
1162 expType = varOp.getType();
1164 llvm_unreachable(
"all in ParentOneOf handled");
1167 auto actType = getOperand().getType();
1168 if (expType != actType) {
1169 return emitOpError() <<
"yields " << actType <<
", but parent expects "
1179OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1181 if (getInput().getType() == getResult().getType())
1185 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1186 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1187 auto toIntType = dyn_cast<IntType>(getResult().getType());
1188 if (intInput && fromIntType && toIntType &&
1189 fromIntType.getWidth() == toIntType.getWidth()) {
1192 if (toIntType.getDomain() == Domain::FourValued)
1197 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1207OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1209 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1210 return reverseOp.getInput();
1214 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1215 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1224OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1229 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1239OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1241 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1242 return reverseOp.getInput();
1245 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1246 return FVIntegerAttr::get(getContext(), attr.getValue());
1255OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1257 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1258 return reverseOp.getInput();
1261 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1262 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1272OpFoldResult ConvertRealOp::fold(FoldAdaptor adaptor) {
1273 if (getInput().getType() == getResult().getType())
1283OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1285 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1286 auto width = getType().getWidth();
1287 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1297OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1299 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1300 auto width = getType().getWidth();
1301 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1311OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1313 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1314 auto width = getType().getWidth();
1315 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1325OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1327 if (getInput().getType() == getResult().getType())
1336bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1338bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1339 return getDst() == slot.ptr;
1342Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1344 const DataLayout &dataLayout) {
1348bool BlockingAssignOp::canUsesBeRemoved(
1349 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1350 SmallVectorImpl<OpOperand *> &newBlockingUses,
1351 const DataLayout &dataLayout) {
1353 if (blockingUses.size() != 1)
1355 Value blockingUse = (*blockingUses.begin())->
get();
1356 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1357 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1360DeletionKind BlockingAssignOp::removeBlockingUses(
1361 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1362 OpBuilder &builder, Value reachingDefinition,
1363 const DataLayout &dataLayout) {
1364 return DeletionKind::Delete;
1371bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1372 return getInput() == slot.ptr;
1375bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1377Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1378 Value reachingDef,
const DataLayout &dataLayout) {
1379 llvm_unreachable(
"getStored should not be called on ReadOp");
1382bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1383 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1384 SmallVectorImpl<OpOperand *> &newBlockingUses,
1385 const DataLayout &dataLayout) {
1387 if (blockingUses.size() != 1)
1389 Value blockingUse = (*blockingUses.begin())->
get();
1390 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1391 getResult().getType() == slot.elemType;
1395ReadOp::removeBlockingUses(
const MemorySlot &slot,
1396 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1397 OpBuilder &builder, Value reachingDefinition,
1398 const DataLayout &dataLayout) {
1399 getResult().replaceAllUsesWith(reachingDefinition);
1400 return DeletionKind::Delete;
1409 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1410 if (lhsValue && lhsValue.getValue() == 1)
1413 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1414 if (rhsValue && rhsValue.getValue().isZero())
1415 return FVIntegerAttr::get(ctxt,
1416 FVInt(rhsValue.getValue().getBitWidth(), 1));
1421OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1425LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1426 Location loc = op.getLoc();
1427 auto intType = cast<IntType>(op.getRhs().getType());
1428 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1429 if (baseOp.getValue() == 2) {
1430 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1431 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1432 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1433 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1434 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1435 op, op.getLhs().getType(), isNegative);
1436 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1437 rewriter.setInsertionPointToStart(thenBlock);
1438 YieldOp::create(rewriter, loc, constZero);
1439 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1440 rewriter.setInsertionPointToStart(elseBlock);
1441 YieldOp::create(rewriter, loc, shift);
1453OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1457LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1458 Location loc = op.getLoc();
1459 auto intType = cast<IntType>(op.getRhs().getType());
1460 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1461 if (baseOp.getValue() == 2) {
1462 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1463 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1475OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1476 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1477 if (intAttr.getValue().isZero())
1487OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1488 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1489 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1491 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1499OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1500 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1501 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1503 return FVIntegerAttr::get(getContext(),
1504 lhs.getValue().udiv(rhs.getValue()));
1512OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1513 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1514 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1516 return FVIntegerAttr::get(getContext(),
1517 lhs.getValue().sdiv(rhs.getValue()));
1525LogicalResult ClassDeclOp::verify() {
1526 mlir::Region &body = getBody();
1528 return mlir::success();
1530 auto &block = body.front();
1531 for (mlir::Operation &op : block) {
1534 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1535 circt::moore::ClassMethodDeclOp>(&op))
1538 return emitOpError()
1539 <<
"body may only contain 'moore.class.propertydecl' operations";
1541 return mlir::success();
1544LogicalResult ClassNewOp::verify() {
1547 auto handleTy = cast<ClassHandleType>(getResult().getType());
1548 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1550 return emitOpError(
"result type is missing a class symbol");
1553 mlir::Operation *sym =
1554 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1556 return emitOpError(
"referenced class symbol `")
1557 << classSym <<
"` was not found";
1559 if (!llvm::isa<ClassDeclOp>(sym))
1560 return emitOpError(
"symbol `")
1561 << classSym <<
"` does not name a `moore.class.classdecl`";
1563 return mlir::success();
1566void ClassNewOp::getEffects(
1567 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1570 effects.emplace_back(MemoryEffects::Allocate::get());
1574ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1576 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1578 return emitOpError() <<
"operand must be !moore.class<...>; got "
1579 << getOperand().getType();
1581 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1583 return emitOpError() <<
"result must be !moore.class<...>; got "
1584 << getResult().getType();
1589 auto *op = getOperation();
1592 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1594 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1595 if (!srcDeclOp || !dstDeclOp)
1596 return emitOpError() <<
"failed to resolve class symbol(s): src="
1597 << srcTy.getClassSym()
1598 <<
", dst=" << dstTy.getClassSym();
1600 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1601 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1602 if (!srcDecl || !dstDecl)
1603 return emitOpError()
1604 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1605 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1612 auto baseSym = cur.getBaseAttr();
1616 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1617 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1620 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1621 << dstTy.getClassSym()
1622 <<
" (destination is not a base class)";
1626ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1628 Type instTy = getInstance().getType();
1629 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1631 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1635 SymbolRefAttr classSym = handleTy.getClassSym();
1637 return emitOpError(
"instance type is missing a class symbol");
1641 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1643 return emitOpError(
"referenced class symbol `")
1644 << classSym <<
"` was not found";
1645 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1647 return emitOpError(
"symbol `")
1648 << classSym <<
"` does not name a `moore.class.classdecl`";
1651 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1653 return emitOpError(
"missing field symbol");
1655 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1657 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1659 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1661 return emitOpError(
"symbol `")
1662 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1665 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1667 return emitOpError(
"result must be a !moore.ref<T>");
1669 Type expectedElemTy = fieldDecl.getPropertyType();
1670 if (resRefTy.getNestedType() != expectedElemTy)
1671 return emitOpError(
"result element type (")
1672 << resRefTy.getNestedType() <<
") does not match field type ("
1673 << expectedElemTy <<
")";
1679VTableLoadMethodOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1680 Operation *op = getOperation();
1682 auto object = getObject();
1683 auto implSym =
object.getType().getClassSym();
1686 Operation *implOp = symbolTable.lookupNearestSymbolFrom(op, implSym);
1688 return emitOpError() <<
"implementing class " << implSym <<
" not found";
1689 auto implClass = cast<moore::ClassDeclOp>(implOp);
1691 StringAttr methodName = getMethodSymAttr().getLeafReference();
1692 if (!methodName || methodName.getValue().empty())
1693 return emitOpError() <<
"empty method name";
1695 moore::ClassDeclOp cursor = implClass;
1696 Operation *methodDeclOp =
nullptr;
1699 while (cursor && !methodDeclOp) {
1700 methodDeclOp = symbolTable.lookupSymbolIn(cursor, methodName);
1703 SymbolRefAttr baseSym = cursor.getBaseAttr();
1706 Operation *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1707 cursor = baseOp ? cast<moore::ClassDeclOp>(baseOp) : moore::ClassDeclOp();
1711 return emitOpError() <<
"no method `" << methodName <<
"` found in "
1712 << implClass.getSymName() <<
" or its bases";
1715 auto methodDecl = dyn_cast<moore::ClassMethodDeclOp>(methodDeclOp);
1717 return emitOpError() <<
"`" << methodName
1718 <<
"` is not a method declaration";
1721 auto resFnTy = cast<FunctionType>(getResult().getType());
1722 auto declFnTy = cast<FunctionType>(methodDecl.getFunctionType());
1723 if (resFnTy != declFnTy)
1724 return emitOpError() <<
"result type " << resFnTy
1725 <<
" does not match method erased ABI " << declFnTy;
1730LogicalResult VTableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1731 Operation *self = getOperation();
1734 SymbolRefAttr name = getSymNameAttr();
1736 return emitOpError(
"requires 'sym_name' SymbolRefAttr");
1739 Operation *rootDef = symbolTable.lookupNearestSymbolFrom(
1740 self, SymbolRefAttr::get(name.getRootReference()));
1742 return emitOpError() <<
"cannot resolve root class symbol '"
1743 << name.getRootReference() <<
"' for sym_name "
1746 if (!isa<ClassDeclOp>(rootDef))
1747 return emitOpError()
1748 <<
"root of sym_name must name a 'moore.class.classdecl', got "
1755LogicalResult VTableOp::verifyRegions() {
1757 for (Operation &op : getBody().front()) {
1758 if (!isa<VTableOp, VTableEntryOp>(op))
1760 "body may only contain 'moore.vtable' or 'moore.vtable_entry' ops");
1762 return mlir::success();
1766VTableEntryOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1767 Operation *self = getOperation();
1771 SymbolRefAttr target = getTargetAttr();
1773 symbolTable.lookupNearestSymbolFrom<func::FuncOp>(self, target);
1775 return emitOpError()
1776 <<
"cannot resolve target symbol to a function operation " << target;
1779 if (!isa<VTableOp>(self->getParentOp()))
1780 return emitOpError(
"must be nested directly inside a 'moore.vtable' op");
1782 Operation *currentOp = self;
1783 VTableOp currentVTable;
1784 bool defined =
false;
1791 while (
auto parentOp = dyn_cast<VTableOp>(currentOp->getParentOp())) {
1792 currentOp = parentOp;
1793 currentVTable = cast<VTableOp>(currentOp);
1795 auto classSymName = currentVTable.getSymName();
1796 ClassDeclOp parentClassDecl =
1797 symbolTable.lookupNearestSymbolFrom<ClassDeclOp>(
1798 parentOp, classSymName.getRootReference());
1799 assert(parentClassDecl &&
"VTableOp must point to a classdeclop");
1801 for (
auto method : parentClassDecl.getBody().getOps<ClassMethodDeclOp>()) {
1803 if (!method.getImpl())
1807 if (method.getSymName() ==
getName() && method.getImplAttr() == target)
1815 else if (method.getSymName() ==
getName() &&
1816 method.getImplAttr() != target && defined)
1817 return emitOpError() <<
"Target " << target
1818 <<
" should be overridden by " << classSymName;
1822 return emitOpError()
1823 <<
"Parent class does not point to any implementation!";
1828LogicalResult DynQueueExtractOp::verify() {
1829 auto elementType = cast<QueueType>(getInput().getType()).getElementType();
1833 if (getResult().getType() ==
elementType && getLowerIdx() != getUpperIdx()) {
1840LogicalResult QueueResizeOp::verify() {
1841 if (cast<QueueType>(getInput().getType()).getElementType() !=
1842 cast<QueueType>(getResult().getType()).getElementType())
1848LogicalResult QueueFromUnpackedArrayOp::verify() {
1850 auto queueElementType =
1851 cast<QueueType>(getResult().getType()).getElementType();
1853 auto arrayElementType =
1854 cast<UnpackedArrayType>(getInput().getType()).getElementType();
1856 if (queueElementType != arrayElementType) {
1857 return emitOpError()
1858 <<
"Queue element type doesn't match unpacked array element type";
1864LogicalResult QueueConcatOp::verify() {
1868 auto resultElType = cast<QueueType>(getResult().getType()).getElementType();
1870 for (Value input : getInputs()) {
1871 auto inpElType = cast<QueueType>(input.getType()).getElementType();
1872 if (inpElType != resultElType) {
1873 return emitOpError() <<
"Queue element type " << inpElType
1874 <<
" doesn't match result element type "
1882void DPIFuncOp::build(OpBuilder &odsBuilder, OperationState &odsState,
1883 StringAttr symName, ArrayRef<DPIArgInfo> dpiArgs,
1884 ArrayAttr argumentLocs, StringAttr verilogName) {
1885 auto *ctx = odsBuilder.getContext();
1886 odsState.addAttribute(getSymNameAttrName(odsState.name), symName);
1889 SmallVector<Type> inputTypes, resultTypes;
1890 SmallVector<Attribute> dirAttrs, nameAttrs;
1891 for (
auto &arg : dpiArgs) {
1892 dirAttrs.push_back(DPIArgDirectionAttr::get(ctx, arg.dir));
1893 nameAttrs.push_back(arg.name);
1895 inputTypes.push_back(arg.type);
1896 if (arg.dir == DPIArgDirection::Out || arg.dir == DPIArgDirection::InOut ||
1897 arg.dir == DPIArgDirection::Return)
1898 resultTypes.push_back(arg.type);
1901 odsState.addAttribute(
1902 getFunctionTypeAttrName(odsState.name),
1903 TypeAttr::get(FunctionType::get(ctx, inputTypes, resultTypes)));
1904 odsState.addAttribute(getDpiArgDirsAttrName(odsState.name),
1905 odsBuilder.getArrayAttr(dirAttrs));
1906 odsState.addAttribute(getDpiArgNamesAttrName(odsState.name),
1907 odsBuilder.getArrayAttr(nameAttrs));
1910 odsState.addAttribute(getArgumentLocsAttrName(odsState.name), argumentLocs);
1912 odsState.addAttribute(getVerilogNameAttrName(odsState.name), verilogName);
1913 odsState.addRegion();
1918 return llvm::StringSwitch<std::optional<DPIArgDirection>>(keyword)
1919 .Case(
"in", DPIArgDirection::In)
1920 .Case(
"out", DPIArgDirection::Out)
1921 .Case(
"inout", DPIArgDirection::InOut)
1922 .Case(
"return", DPIArgDirection::Return)
1923 .Default(std::nullopt);
1929 case DPIArgDirection::In:
1931 case DPIArgDirection::Out:
1933 case DPIArgDirection::InOut:
1935 case DPIArgDirection::Return:
1938 llvm_unreachable(
"unknown DPIArgDirection");
1941ParseResult DPIFuncOp::parse(OpAsmParser &parser, OperationState &result) {
1942 auto builder = parser.getBuilder();
1943 auto ctx = builder.getContext();
1945 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1947 StringAttr nameAttr;
1948 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1952 SmallVector<DPIArgDirection> argDirs;
1953 SmallVector<StringAttr> argNames;
1954 SmallVector<Type> argTypes;
1955 SmallVector<Attribute> argLocs;
1956 auto unknownLoc = builder.getUnknownLoc();
1957 bool hasLocs =
false;
1959 auto parseOneArg = [&]() -> ParseResult {
1960 StringRef dirKeyword;
1961 auto keyLoc = parser.getCurrentLocation();
1962 if (parser.parseKeyword(&dirKeyword))
1966 return parser.emitError(keyLoc,
1967 "expected DPI argument direction keyword");
1970 bool hasSSA = DPIFuncOp::isCallOperandDir(*dir);
1971 std::string argName;
1973 OpAsmParser::UnresolvedOperand ssaName;
1974 if (parser.parseOperand(ssaName,
false))
1976 argName = ssaName.name.substr(1).str();
1978 if (parser.parseKeywordOrString(&argName))
1983 if (parser.parseColonType(argType))
1986 argDirs.push_back(*dir);
1987 argNames.push_back(StringAttr::get(ctx, argName));
1988 argTypes.push_back(argType);
1990 std::optional<Location> maybeLoc;
1991 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1994 argLocs.push_back(*maybeLoc);
1997 argLocs.push_back(unknownLoc);
2002 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOneArg,
2003 " in DPI argument list"))
2007 SmallVector<Type> inputTypes, resultTypes;
2008 for (
auto [dir, type] :
llvm::zip(argDirs, argTypes)) {
2009 if (DPIFuncOp::isCallOperandDir(dir))
2010 inputTypes.push_back(type);
2011 if (dir == DPIArgDirection::Out || dir == DPIArgDirection::InOut ||
2012 dir == DPIArgDirection::Return)
2013 resultTypes.push_back(type);
2015 auto funcType = FunctionType::get(ctx, inputTypes, resultTypes);
2016 result.addAttribute(DPIFuncOp::getFunctionTypeAttrName(result.name),
2017 TypeAttr::get(funcType));
2020 SmallVector<Attribute> dirAttrs;
2021 for (
auto d : argDirs)
2022 dirAttrs.push_back(DPIArgDirectionAttr::
get(ctx,
d));
2023 result.addAttribute(DPIFuncOp::getDpiArgDirsAttrName(result.name),
2024 builder.getArrayAttr(dirAttrs));
2027 SmallVector<Attribute> nameAttrs(argNames.begin(), argNames.end());
2028 result.addAttribute(DPIFuncOp::getDpiArgNamesAttrName(result.name),
2029 builder.getArrayAttr(nameAttrs));
2032 result.addAttribute(DPIFuncOp::getArgumentLocsAttrName(result.name),
2033 builder.getArrayAttr(argLocs));
2036 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2045::mlir::Type DPIFuncOp::cloneTypeWith(::mlir::TypeRange inputs,
2046 ::mlir::TypeRange results) {
2047 return FunctionType::get(getContext(), inputs, results);
2050void DPIFuncOp::getDPIArgTypes(SmallVectorImpl<Type> &argTypes) {
2051 auto funcType = getFunctionType();
2052 auto inputs = funcType.getInputs();
2053 auto results = funcType.getResults();
2054 auto dirs = getDpiArgDirsAttr();
2055 unsigned inputIdx = 0, resultIdx = 0;
2056 for (
auto dirAttr : dirs) {
2057 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2059 case DPIArgDirection::In:
2060 argTypes.push_back(inputs[inputIdx++]);
2062 case DPIArgDirection::Out:
2063 argTypes.push_back(results[resultIdx++]);
2065 case DPIArgDirection::InOut:
2066 argTypes.push_back(inputs[inputIdx++]);
2069 case DPIArgDirection::Return:
2070 argTypes.push_back(results[resultIdx++]);
2076LogicalResult DPIFuncOp::verify() {
2077 auto dirs = getDpiArgDirs();
2078 auto names = getDpiArgNames();
2079 if (dirs.size() != names.size())
2080 return emitOpError(
"argument directions and names must have the same size");
2083 bool seenReturn =
false;
2084 for (
auto [i, dirAttr] :
llvm::enumerate(dirs)) {
2085 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2086 if (dir == DPIArgDirection::Return) {
2088 return emitOpError(
"'return' argument must be the last argument");
2089 if (i != dirs.size() - 1)
2090 return emitOpError(
"'return' argument must be the last argument");
2097void DPIFuncOp::print(OpAsmPrinter &p) {
2100 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2101 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2102 p << visibility.getValue() <<
' ';
2103 p.printSymbolName(getSymName());
2105 auto dirs = getDpiArgDirs();
2106 auto names = getDpiArgNames();
2107 SmallVector<Type> argTypes;
2108 getDPIArgTypes(argTypes);
2111 llvm::interleaveComma(llvm::enumerate(dirs), p, [&](
auto it) {
2112 auto dir = cast<DPIArgDirectionAttr>(it.value()).getValue();
2113 auto i = it.index();
2114 auto name = cast<StringAttr>(names[i]).getValue();
2115 auto type = argTypes[i];
2121 p.printKeywordOrString(name);
2125 if (getArgumentLocs()) {
2126 auto loc = cast<Location>(getArgumentLocsAttr()[i]);
2127 if (loc != UnknownLoc::get(getContext()))
2128 p.printOptionalLocationSpecifier(loc);
2133 mlir::function_interface_impl::printFunctionAttributes(
2135 {visibilityAttrName, getFunctionTypeAttrName(), getDpiArgDirsAttrName(),
2136 getDpiArgNamesAttrName(), getArgumentLocsAttrName()});
2140FuncDPICallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2142 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr());
2144 return emitError(
"cannot find function declaration '")
2145 << getCallee() <<
"'";
2146 if (
auto dpiFunc = dyn_cast<DPIFuncOp>(referencedOp)) {
2147 auto funcType = cast<FunctionType>(dpiFunc.getFunctionType());
2148 auto expectedInputs = funcType.getInputs();
2149 auto expectedResults = funcType.getResults();
2150 if (getInputs().size() != expectedInputs.size())
2151 return emitError(
"expects ")
2152 << expectedInputs.size() <<
" DPI operands, but got "
2153 << getInputs().size();
2154 if (getResults().size() != expectedResults.size())
2155 return emitError(
"expects ")
2156 << expectedResults.size() <<
" DPI results, but got "
2157 << getResults().size();
2158 for (
auto [operand, expectedType] :
llvm::zip(getInputs(), expectedInputs))
2159 if (operand.getType() != expectedType)
2160 return emitError(
"operand type mismatch: expected ")
2161 << expectedType <<
", but got " << operand.getType();
2162 for (
auto [result, expectedType] :
llvm::zip(getResults(), expectedResults))
2163 if (result.getType() != expectedType)
2164 return emitError(
"result type mismatch: expected ")
2165 << expectedType <<
", but got " << result.getType();
2168 if (isa<func::FuncOp>(referencedOp))
2170 return emitError(
"callee must be 'moore.func.dpi' or 'func.func' but got '")
2171 << referencedOp->getName() <<
"'";
2179#define GET_OP_CLASSES
2180#include "circt/Dialect/Moore/Moore.cpp.inc"
2181#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 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.
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.
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