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());
54 p.printRegion(getBodyRegion(),
false,
57 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
61ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
63 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
67 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
72 SmallVector<hw::module_like_impl::PortParse> ports;
77 result.addAttribute(getModuleTypeAttrName(result.name), modType);
80 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
84 SmallVector<OpAsmParser::Argument, 4> entryArgs;
85 for (
auto &port : ports)
87 entryArgs.push_back(port);
90 auto &bodyRegion = *result.addRegion();
91 if (parser.parseRegion(bodyRegion, entryArgs))
94 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
98void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
100 if (®ion != &getBodyRegion())
103 for (
auto [index, arg] :
llvm::enumerate(region.front().getArguments()))
104 setNameFn(arg, moduleType.getInputNameAttr(index));
107OutputOp SVModuleOp::getOutputOp() {
108 return cast<OutputOp>(getBody()->getTerminator());
111OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
117LogicalResult OutputOp::verify() {
118 auto module = getParentOp();
121 auto outputTypes =
module.getModuleType().getOutputTypes();
122 if (outputTypes.size() != getNumOperands())
123 return emitOpError(
"has ")
124 << getNumOperands() <<
" operands, but enclosing module @"
125 <<
module.getSymName() << " has " << outputTypes.size()
129 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
130 if (outputTypes[i] != getOperand(i).getType())
131 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
132 <<
") does not match output type (" << outputTypes[i]
133 <<
") of module @" <<
module.getSymName();
142LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
145 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
147 return emitOpError(
"references unknown symbol @") << getModuleName();
150 auto module = dyn_cast<SVModuleOp>(symbol);
152 return emitOpError(
"must reference a 'moore.module', but @")
153 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
156 auto moduleType =
module.getModuleType();
157 auto inputTypes = moduleType.getInputTypes();
159 if (inputTypes.size() != getNumOperands())
160 return emitOpError(
"has ")
161 << getNumOperands() <<
" operands, but target module @"
162 <<
module.getSymName() << " has " << inputTypes.size() << " inputs";
164 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
165 if (inputTypes[i] != getOperand(i).getType())
166 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
167 <<
") does not match input type (" << inputTypes[i]
168 <<
") of module @" <<
module.getSymName();
171 auto outputTypes = moduleType.getOutputTypes();
173 if (outputTypes.size() != getNumResults())
174 return emitOpError(
"has ")
175 << getNumOperands() <<
" results, but target module @"
176 <<
module.getSymName() << " has " << outputTypes.size()
179 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
180 if (outputTypes[i] != getResult(i).getType())
181 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
182 <<
") does not match output type (" << outputTypes[i]
183 <<
") of module @" <<
module.getSymName();
188void InstanceOp::print(OpAsmPrinter &p) {
190 p.printAttributeWithoutType(getInstanceNameAttr());
192 p.printAttributeWithoutType(getModuleNameAttr());
198 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
201ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
203 StringAttr instanceName;
204 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
208 FlatSymbolRefAttr moduleName;
209 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
213 auto loc = parser.getCurrentLocation();
214 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
215 SmallVector<Type> types;
219 if (parser.resolveOperands(inputs, types, loc, result.operands))
221 result.addAttribute(
"inputNames", names);
224 if (parser.parseArrow())
231 result.addAttribute(
"outputNames", names);
232 result.addTypes(types);
235 if (parser.parseOptionalAttrDict(result.attributes))
242 SmallString<32> name;
245 auto baseLen = name.size();
247 for (
auto [result, portName] :
248 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
249 if (!portName || portName.empty())
251 name.resize(baseLen);
252 name += portName.getValue();
253 setNameFn(result, name);
261ParseResult CoroutineOp::parse(OpAsmParser &parser, OperationState &result) {
263 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
264 function_interface_impl::VariadicFlag,
265 std::string &) {
return builder.getFunctionType(argTypes, results); };
267 return function_interface_impl::parseFunctionOp(
268 parser, result,
false,
269 getFunctionTypeAttrName(result.name), buildFuncType,
270 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
273void CoroutineOp::print(OpAsmPrinter &p) {
274 function_interface_impl::printFunctionOp(
275 p, *
this,
false, getFunctionTypeAttrName(),
276 getArgAttrsAttrName(), getResAttrsAttrName());
284CallCoroutineOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
285 auto calleeName = getCalleeAttr();
287 symbolTable.lookupNearestSymbolFrom<CoroutineOp>(*
this, calleeName);
289 return emitOpError() <<
"'" << calleeName.getValue()
290 <<
"' does not reference a valid 'moore.coroutine'";
292 auto type = coroutine.getFunctionType();
293 if (type.getNumInputs() != getNumOperands())
294 return emitOpError() <<
"has " << getNumOperands()
295 <<
" operands, but callee expects "
296 << type.getNumInputs();
298 for (
unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
299 if (getOperand(i).getType() != type.getInput(i))
300 return emitOpError() <<
"operand " << i <<
" type mismatch: expected "
301 << type.getInput(i) <<
", got "
302 << getOperand(i).getType();
304 if (type.getNumResults() != getNumResults())
305 return emitOpError() <<
"has " << getNumResults()
306 <<
" results, but callee returns "
307 << type.getNumResults();
309 for (
unsigned i = 0, e = type.getNumResults(); i != e; ++i)
310 if (getResult(i).getType() != type.getResult(i))
311 return emitOpError() <<
"result " << i <<
" type mismatch: expected "
312 << type.getResult(i) <<
", got "
313 << getResult(i).getType();
324 setNameFn(getResult(), *
getName());
327LogicalResult VariableOp::canonicalize(VariableOp op,
328 PatternRewriter &rewriter) {
332 auto initial = op.getInitial();
333 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
334 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
335 rewriter.setInsertionPointAfter(op);
336 BlockingAssignOp::create(rewriter, initial.getLoc(), op, initial);
343 auto *block = op->getBlock();
344 ContinuousAssignOp uniqueAssignOp;
345 for (
auto *user : op->getUsers()) {
347 if (user->getBlock() != block)
351 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
354 uniqueAssignOp = assignOp;
359 if (!isa<ReadOp>(user))
367 Value assignedValue = uniqueAssignOp.getSrc();
368 if (
auto name = op.getNameAttr(); name && !name.empty())
369 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
370 uniqueAssignOp.getSrc());
373 rewriter.eraseOp(uniqueAssignOp);
374 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
375 auto readOp = cast<ReadOp>(user);
376 rewriter.replaceOp(readOp, assignedValue);
380 rewriter.eraseOp(op);
384SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
387 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
393 auto nestedType = dyn_cast<PackedType>(getType().getNestedType());
394 if (!nestedType || !nestedType.getBitSize())
397 return {MemorySlot{getResult(), getType().getNestedType()}};
400Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
401 auto packedType = dyn_cast<PackedType>(slot.elemType);
404 auto bitWidth = packedType.getBitSize();
407 auto fvint = packedType.getDomain() == Domain::FourValued
409 :
FVInt::getZero(*bitWidth);
410 Value value = ConstantOp::create(
412 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
413 if (value.getType() != packedType)
414 value = SBVToPackedOp::create(builder,
getLoc(), packedType, value);
418void VariableOp::handleBlockArgument(
const MemorySlot &slot,
419 BlockArgument argument,
420 OpBuilder &builder) {}
422std::optional<mlir::PromotableAllocationOpInterface>
423VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
424 OpBuilder &builder) {
425 if (defaultValue && defaultValue.use_empty())
426 defaultValue.getDefiningOp()->erase();
431SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
432 if (isa<SVModuleOp>(getOperation()->getParentOp()))
437 auto refType = getType();
438 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
442 auto destructuredType = destructurable.getSubelementIndexMap();
443 if (!destructuredType)
446 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
449DenseMap<Attribute, MemorySlot> VariableOp::destructure(
450 const DestructurableMemorySlot &slot,
451 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
452 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
453 assert(slot.ptr == getResult());
455 builder.setInsertionPointAfter(*
this);
457 auto destructurableType = cast<DestructurableTypeInterface>(getType());
458 DenseMap<Attribute, MemorySlot> slotMap;
459 for (Attribute index : usedIndices) {
460 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
461 assert(elemType &&
"used index must exist");
463 if (
auto name =
getName(); name && !name->empty())
464 varName = StringAttr::get(
465 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
467 VariableOp::create(builder,
getLoc(), elemType, varName, Value());
468 newAllocators.push_back(varOp);
469 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
475std::optional<DestructurableAllocationOpInterface>
476VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
477 OpBuilder &builder) {
478 assert(slot.ptr == getResult());
489 setNameFn(getResult(), *
getName());
492LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
493 bool modified =
false;
497 auto *block = op->getBlock();
498 ContinuousAssignOp uniqueAssignOp;
499 bool allUsesAreReads =
true;
500 for (
auto *user : op->getUsers()) {
502 if (user->getBlock() != block)
506 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
509 uniqueAssignOp = assignOp;
514 if (!isa<ReadOp>(user))
515 allUsesAreReads =
false;
520 if (uniqueAssignOp && !op.getAssignment()) {
521 rewriter.modifyOpInPlace(
522 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
523 rewriter.eraseOp(uniqueAssignOp);
531 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
534 auto assignedValue = op.getAssignment();
535 if (
auto name = op.getNameAttr(); name && !name.empty())
536 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
541 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
542 auto readOp = cast<ReadOp>(user);
543 rewriter.replaceOp(readOp, assignedValue);
545 rewriter.eraseOp(op);
549 return success(modified);
558 setNameFn(getResult(), *
getName());
561LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
562 PatternRewriter &rewriter) {
565 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
566 if (otherOp != op && otherOp.getNameAttr() == op.getNameAttr()) {
567 rewriter.replaceOp(op, otherOp);
573 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
575 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
576 auto moduleType = moduleOp.getModuleType();
577 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
578 if (portName == op.getNameAttr()) {
579 rewriter.replaceOp(op, blockArg);
586 for (
auto &use : op->getUses()) {
587 auto *useOwner = use.getOwner();
588 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
589 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
590 auto moduleType = moduleOp.getModuleType();
591 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
592 if (portName == op.getNameAttr()) {
593 rewriter.replaceOp(op, op.getInput());
608LogicalResult GlobalVariableOp::verifyRegions() {
609 if (
auto *block = getInitBlock()) {
610 auto &terminator = block->back();
611 if (!isa<YieldOp>(terminator))
612 return emitOpError() <<
"must have a 'moore.yield' terminator";
617Block *GlobalVariableOp::getInitBlock() {
618 if (getInitRegion().
empty())
620 return &getInitRegion().front();
628GetGlobalVariableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
631 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
633 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
636 auto var = dyn_cast<GlobalVariableOp>(symbol);
638 return emitOpError() <<
"must reference a 'moore.global_variable', but "
639 << getGlobalNameAttr() <<
" is a '"
640 << symbol->getName() <<
"'";
643 auto expType = var.getType();
644 auto actType = getType().getNestedType();
645 if (expType != actType)
646 return emitOpError() <<
"returns a " << actType <<
" reference, but "
647 << getGlobalNameAttr() <<
" is of type " << expType;
656void ConstantOp::print(OpAsmPrinter &p) {
659 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
661 p.printStrippedAttrOrType(getType());
664ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
667 auto valueLoc = parser.getCurrentLocation();
672 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
677 if (parser.parseCustomTypeWithFallback(type))
685 value = value.
sext(type.getWidth());
686 }
else if (type.getWidth() < value.
getBitWidth()) {
689 unsigned neededBits =
691 if (type.getWidth() < neededBits)
692 return parser.emitError(valueLoc)
693 <<
"value requires " << neededBits
694 <<
" bits, but result type only has " << type.getWidth();
695 value = value.
trunc(type.getWidth());
700 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
701 return parser.emitError(valueLoc)
702 <<
"value contains X or Z bits, but result type " << type
703 <<
" only allows two-valued bits";
706 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
707 result.addAttribute(
"value", attrValue);
708 result.addTypes(type);
712LogicalResult ConstantOp::verify() {
713 auto attrWidth = getValue().getBitWidth();
714 auto typeWidth = getType().getWidth();
715 if (attrWidth != typeWidth)
716 return emitError(
"attribute width ")
717 << attrWidth <<
" does not match return type's width " << typeWidth;
721void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
722 const FVInt &value) {
724 "FVInt width must match type width");
725 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
728void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
729 const APInt &value) {
730 assert(type.getWidth() == value.getBitWidth() &&
731 "APInt width must match type width");
732 build(builder, result, type,
FVInt(value));
739void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
740 int64_t value,
bool isSigned) {
741 build(builder, result, type,
742 APInt(type.getWidth(), (uint64_t)value, isSigned));
746void ConstantOp::build(OpBuilder &builder, OperationState &result,
747 Domain domain,
bool value) {
748 auto type = IntType::get(builder.getContext(), 1, domain);
749 build(builder, result, type, value ? 1 : 0, false);
752OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
753 assert(adaptor.getOperands().empty() &&
"constant has no operands");
754 return getValueAttr();
761OpFoldResult ConstantTimeOp::fold(FoldAdaptor adaptor) {
762 return getValueAttr();
769LogicalResult ConstantRealOp::inferReturnTypes(
770 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
771 DictionaryAttr attrs, mlir::PropertyRef properties,
772 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
773 ConstantRealOp::Adaptor adaptor(operands, attrs, properties);
774 results.push_back(RealType::get(
776 adaptor.getValueAttr().getType().getIntOrFloatBitWidth())));
784LogicalResult ConcatOp::inferReturnTypes(
785 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
786 DictionaryAttr attrs, mlir::PropertyRef properties,
787 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
788 Domain domain = Domain::TwoValued;
790 for (
auto operand : operands) {
791 auto type = cast<IntType>(operand.getType());
792 if (type.getDomain() == Domain::FourValued)
793 domain = Domain::FourValued;
794 width += type.getWidth();
796 results.push_back(IntType::get(
context, width, domain));
804LogicalResult ConcatRefOp::inferReturnTypes(
805 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
806 DictionaryAttr attrs, mlir::PropertyRef properties,
807 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
808 Domain domain = Domain::TwoValued;
810 for (Value operand : operands) {
811 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
812 PackedType packedType = dyn_cast<PackedType>(nestedType);
818 if (packedType.
getDomain() == Domain::FourValued)
819 domain = Domain::FourValued;
822 std::optional<int> bitSize = packedType.
getBitSize();
828 results.push_back(RefType::get(IntType::get(
context, width, domain)));
837 if (
auto arrayType = dyn_cast<ArrayType>(type))
838 return {arrayType.getSize(), arrayType.getElementType()};
839 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
840 return {arrayType.getSize(), arrayType.getElementType()};
841 assert(0 &&
"expected ArrayType or UnpackedArrayType");
845LogicalResult ArrayCreateOp::verify() {
849 if (getElements().size() != size)
850 return emitOpError() <<
"has " << getElements().size()
851 <<
" operands, but result type requires " << size;
857 auto value = getElements()[0];
859 return emitOpError() <<
"operands have type " << value.getType()
870 if (
auto structType = dyn_cast<StructType>(type))
871 return structType.getFieldIndex(name);
872 if (
auto structType = dyn_cast<UnpackedStructType>(type))
873 return structType.getFieldIndex(name);
874 assert(0 &&
"expected StructType or UnpackedStructType");
879 if (
auto structType = dyn_cast<StructType>(type))
880 return structType.getMembers();
881 if (
auto structType = dyn_cast<UnpackedStructType>(type))
882 return structType.getMembers();
883 assert(0 &&
"expected StructType or UnpackedStructType");
893LogicalResult StructCreateOp::verify() {
897 if (getFields().size() != members.size())
898 return emitOpError() <<
"has " << getFields().size()
899 <<
" operands, but result type requires "
903 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
904 auto [value, member] = pair;
905 if (value.getType() != member.type)
906 return emitOpError() <<
"operand #" << index <<
" has type "
907 << value.getType() <<
", but struct field "
908 << member.name <<
" requires " << member.type;
913OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
914 SmallVector<NamedAttribute> fields;
915 for (
auto [member, field] :
919 fields.push_back(NamedAttribute(member.name, field));
921 return DictionaryAttr::get(getContext(), fields);
928LogicalResult StructExtractOp::verify() {
931 return emitOpError() <<
"extracts field " << getFieldNameAttr()
932 <<
" which does not exist in " << getInput().getType();
933 if (type != getType())
934 return emitOpError() <<
"result type " << getType()
935 <<
" must match struct field type " << type;
939OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
941 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
942 if (
auto value = fields.get(getFieldNameAttr()))
946 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
947 if (inject.getFieldNameAttr() == getFieldNameAttr())
948 return inject.getNewValue();
953 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
955 return create.getFields()[*index];
966LogicalResult StructExtractRefOp::verify() {
968 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
970 return emitOpError() <<
"extracts field " << getFieldNameAttr()
971 <<
" which does not exist in " << getInput().getType();
972 if (type != getType().getNestedType())
973 return emitOpError() <<
"result ref of type " << getType().getNestedType()
974 <<
" must match struct field type " << type;
978bool StructExtractRefOp::canRewire(
979 const DestructurableMemorySlot &slot,
980 SmallPtrSetImpl<Attribute> &usedIndices,
981 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
982 const DataLayout &dataLayout) {
983 if (slot.ptr != getInput())
985 auto index = getFieldNameAttr();
986 if (!index || !slot.subelementTypes.contains(index))
988 usedIndices.insert(index);
993StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
994 DenseMap<Attribute, MemorySlot> &subslots,
995 OpBuilder &builder,
const DataLayout &dataLayout) {
996 auto index = getFieldNameAttr();
997 const MemorySlot &memorySlot = subslots.at(index);
998 replaceAllUsesWith(memorySlot.ptr);
999 getInputMutable().drop();
1001 return DeletionKind::Keep;
1008LogicalResult StructInjectOp::verify() {
1011 return emitOpError() <<
"injects field " << getFieldNameAttr()
1012 <<
" which does not exist in " << getInput().getType();
1013 if (type != getNewValue().getType())
1014 return emitOpError() <<
"injected value " << getNewValue().getType()
1015 <<
" must match struct field type " << type;
1019OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
1020 auto input = adaptor.getInput();
1021 auto newValue = adaptor.getNewValue();
1022 if (!input || !newValue)
1024 NamedAttrList fields(cast<DictionaryAttr>(input));
1025 fields.set(getFieldNameAttr(), newValue);
1026 return fields.getDictionary(getContext());
1029LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
1030 PatternRewriter &rewriter) {
1035 SmallPtrSet<Operation *, 4> injectOps;
1036 DenseMap<StringAttr, Value> fieldValues;
1038 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
1039 if (!injectOps.insert(injectOp).second)
1041 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
1042 input = injectOp.getInput();
1044 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
1045 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
1046 fieldValues.insert({member.name, value});
1049 if (fieldValues.size() == members.size()) {
1050 SmallVector<Value> values;
1051 values.reserve(fieldValues.size());
1052 for (
auto member : members)
1053 values.push_back(fieldValues.lookup(member.name));
1054 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
1060 if (injectOps.size() == fieldValues.size())
1065 for (
auto member : members)
1066 if (auto value = fieldValues.lookup(member.name))
1067 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
1068 member.name, value);
1069 rewriter.replaceOp(op, input);
1077LogicalResult UnionCreateOp::verify() {
1080 return TypeSwitch<Type, LogicalResult>(getType())
1081 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1082 auto members = type.getMembers();
1083 auto inputType = getInput().getType();
1085 for (
const auto &member : members)
1086 if (member.name == fieldName && member.type == inputType)
1088 for (
const auto &member : members) {
1089 if (member.name == fieldName) {
1090 emitOpError() <<
"input type " << inputType
1091 <<
" does not match union field '" << fieldName
1092 <<
"' type " << member.type;
1096 emitOpError() <<
"field '" << fieldName <<
"' not found in union type";
1099 .Default([
this](
auto &) {
1100 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1109LogicalResult UnionExtractOp::verify() {
1112 return TypeSwitch<Type, LogicalResult>(getInput().getType())
1113 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1114 auto members = type.getMembers();
1116 auto resultType = getType();
1117 for (
const auto &member : members)
1118 if (member.name == fieldName && member.type == resultType)
1120 emitOpError(
"result type must match the union field type");
1123 .Default([
this](
auto &) {
1124 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1133LogicalResult UnionExtractRefOp::verify() {
1136 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1137 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1138 auto members = type.getMembers();
1140 auto resultType = getType().getNestedType();
1141 for (
const auto &member : members)
1142 if (member.name == fieldName && member.type == resultType)
1144 emitOpError(
"result type must match the union field type");
1147 .Default([
this](
auto &) {
1148 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1157LogicalResult YieldOp::verify() {
1159 auto *parentOp = getOperation()->getParentOp();
1160 if (
auto cond = dyn_cast<ConditionalOp>(parentOp)) {
1161 expType = cond.getType();
1162 }
else if (
auto varOp = dyn_cast<GlobalVariableOp>(parentOp)) {
1163 expType = varOp.getType();
1165 llvm_unreachable(
"all in ParentOneOf handled");
1168 auto actType = getOperand().getType();
1169 if (expType != actType) {
1170 return emitOpError() <<
"yields " << actType <<
", but parent expects "
1180OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1182 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1183 return reverseOp.getInput();
1187 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1188 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1197OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1202 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1212OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1214 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1215 return reverseOp.getInput();
1218 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1219 return FVIntegerAttr::get(getContext(), attr.getValue());
1228OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1230 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1231 return reverseOp.getInput();
1234 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1235 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1245OpFoldResult ConvertRealOp::fold(FoldAdaptor adaptor) {
1246 if (getInput().getType() == getResult().getType())
1256OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1258 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1259 auto width = getType().getWidth();
1260 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1270OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1272 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1273 auto width = getType().getWidth();
1274 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1284OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1286 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1287 auto width = getType().getWidth();
1288 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1298OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1300 if (getInput().getType() == getResult().getType())
1309bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1311bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1312 return getDst() == slot.ptr;
1315Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1317 const DataLayout &dataLayout) {
1321bool BlockingAssignOp::canUsesBeRemoved(
1322 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1323 SmallVectorImpl<OpOperand *> &newBlockingUses,
1324 const DataLayout &dataLayout) {
1326 if (blockingUses.size() != 1)
1328 Value blockingUse = (*blockingUses.begin())->
get();
1329 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1330 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1333DeletionKind BlockingAssignOp::removeBlockingUses(
1334 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1335 OpBuilder &builder, Value reachingDefinition,
1336 const DataLayout &dataLayout) {
1337 return DeletionKind::Delete;
1344bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1345 return getInput() == slot.ptr;
1348bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1350Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1351 Value reachingDef,
const DataLayout &dataLayout) {
1352 llvm_unreachable(
"getStored should not be called on ReadOp");
1355bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1356 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1357 SmallVectorImpl<OpOperand *> &newBlockingUses,
1358 const DataLayout &dataLayout) {
1360 if (blockingUses.size() != 1)
1362 Value blockingUse = (*blockingUses.begin())->
get();
1363 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1364 getResult().getType() == slot.elemType;
1368ReadOp::removeBlockingUses(
const MemorySlot &slot,
1369 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1370 OpBuilder &builder, Value reachingDefinition,
1371 const DataLayout &dataLayout) {
1372 getResult().replaceAllUsesWith(reachingDefinition);
1373 return DeletionKind::Delete;
1382 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1383 if (lhsValue && lhsValue.getValue() == 1)
1386 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1387 if (rhsValue && rhsValue.getValue().isZero())
1388 return FVIntegerAttr::get(ctxt,
1389 FVInt(rhsValue.getValue().getBitWidth(), 1));
1394OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1398LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1399 Location loc = op.getLoc();
1400 auto intType = cast<IntType>(op.getRhs().getType());
1401 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1402 if (baseOp.getValue() == 2) {
1403 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1404 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1405 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1406 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1407 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1408 op, op.getLhs().getType(), isNegative);
1409 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1410 rewriter.setInsertionPointToStart(thenBlock);
1411 YieldOp::create(rewriter, loc, constZero);
1412 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1413 rewriter.setInsertionPointToStart(elseBlock);
1414 YieldOp::create(rewriter, loc, shift);
1426OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1430LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1431 Location loc = op.getLoc();
1432 auto intType = cast<IntType>(op.getRhs().getType());
1433 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1434 if (baseOp.getValue() == 2) {
1435 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1436 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1448OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1449 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1450 if (intAttr.getValue().isZero())
1460OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1461 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1462 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1464 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1472OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1473 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1474 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1476 return FVIntegerAttr::get(getContext(),
1477 lhs.getValue().udiv(rhs.getValue()));
1485OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1486 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1487 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1489 return FVIntegerAttr::get(getContext(),
1490 lhs.getValue().sdiv(rhs.getValue()));
1498LogicalResult ClassDeclOp::verify() {
1499 mlir::Region &body = getBody();
1501 return mlir::success();
1503 auto &block = body.front();
1504 for (mlir::Operation &op : block) {
1507 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1508 circt::moore::ClassMethodDeclOp>(&op))
1511 return emitOpError()
1512 <<
"body may only contain 'moore.class.propertydecl' operations";
1514 return mlir::success();
1517LogicalResult ClassNewOp::verify() {
1520 auto handleTy = cast<ClassHandleType>(getResult().getType());
1521 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1523 return emitOpError(
"result type is missing a class symbol");
1526 mlir::Operation *sym =
1527 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1529 return emitOpError(
"referenced class symbol `")
1530 << classSym <<
"` was not found";
1532 if (!llvm::isa<ClassDeclOp>(sym))
1533 return emitOpError(
"symbol `")
1534 << classSym <<
"` does not name a `moore.class.classdecl`";
1536 return mlir::success();
1539void ClassNewOp::getEffects(
1540 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1543 effects.emplace_back(MemoryEffects::Allocate::get());
1547ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1549 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1551 return emitOpError() <<
"operand must be !moore.class<...>; got "
1552 << getOperand().getType();
1554 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1556 return emitOpError() <<
"result must be !moore.class<...>; got "
1557 << getResult().getType();
1562 auto *op = getOperation();
1565 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1567 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1568 if (!srcDeclOp || !dstDeclOp)
1569 return emitOpError() <<
"failed to resolve class symbol(s): src="
1570 << srcTy.getClassSym()
1571 <<
", dst=" << dstTy.getClassSym();
1573 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1574 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1575 if (!srcDecl || !dstDecl)
1576 return emitOpError()
1577 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1578 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1585 auto baseSym = cur.getBaseAttr();
1589 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1590 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1593 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1594 << dstTy.getClassSym()
1595 <<
" (destination is not a base class)";
1599ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1601 Type instTy = getInstance().getType();
1602 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1604 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1608 SymbolRefAttr classSym = handleTy.getClassSym();
1610 return emitOpError(
"instance type is missing a class symbol");
1614 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1616 return emitOpError(
"referenced class symbol `")
1617 << classSym <<
"` was not found";
1618 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1620 return emitOpError(
"symbol `")
1621 << classSym <<
"` does not name a `moore.class.classdecl`";
1624 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1626 return emitOpError(
"missing field symbol");
1628 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1630 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1632 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1634 return emitOpError(
"symbol `")
1635 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1638 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1640 return emitOpError(
"result must be a !moore.ref<T>");
1642 Type expectedElemTy = fieldDecl.getPropertyType();
1643 if (resRefTy.getNestedType() != expectedElemTy)
1644 return emitOpError(
"result element type (")
1645 << resRefTy.getNestedType() <<
") does not match field type ("
1646 << expectedElemTy <<
")";
1652VTableLoadMethodOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1653 Operation *op = getOperation();
1655 auto object = getObject();
1656 auto implSym =
object.getType().getClassSym();
1659 Operation *implOp = symbolTable.lookupNearestSymbolFrom(op, implSym);
1661 return emitOpError() <<
"implementing class " << implSym <<
" not found";
1662 auto implClass = cast<moore::ClassDeclOp>(implOp);
1664 StringAttr methodName = getMethodSymAttr().getLeafReference();
1665 if (!methodName || methodName.getValue().empty())
1666 return emitOpError() <<
"empty method name";
1668 moore::ClassDeclOp cursor = implClass;
1669 Operation *methodDeclOp =
nullptr;
1672 while (cursor && !methodDeclOp) {
1673 methodDeclOp = symbolTable.lookupSymbolIn(cursor, methodName);
1676 SymbolRefAttr baseSym = cursor.getBaseAttr();
1679 Operation *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1680 cursor = baseOp ? cast<moore::ClassDeclOp>(baseOp) : moore::ClassDeclOp();
1684 return emitOpError() <<
"no method `" << methodName <<
"` found in "
1685 << implClass.getSymName() <<
" or its bases";
1688 auto methodDecl = dyn_cast<moore::ClassMethodDeclOp>(methodDeclOp);
1690 return emitOpError() <<
"`" << methodName
1691 <<
"` is not a method declaration";
1694 auto resFnTy = cast<FunctionType>(getResult().getType());
1695 auto declFnTy = cast<FunctionType>(methodDecl.getFunctionType());
1696 if (resFnTy != declFnTy)
1697 return emitOpError() <<
"result type " << resFnTy
1698 <<
" does not match method erased ABI " << declFnTy;
1703LogicalResult VTableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1704 Operation *self = getOperation();
1707 SymbolRefAttr name = getSymNameAttr();
1709 return emitOpError(
"requires 'sym_name' SymbolRefAttr");
1712 Operation *rootDef = symbolTable.lookupNearestSymbolFrom(
1713 self, SymbolRefAttr::get(name.getRootReference()));
1715 return emitOpError() <<
"cannot resolve root class symbol '"
1716 << name.getRootReference() <<
"' for sym_name "
1719 if (!isa<ClassDeclOp>(rootDef))
1720 return emitOpError()
1721 <<
"root of sym_name must name a 'moore.class.classdecl', got "
1728LogicalResult VTableOp::verifyRegions() {
1730 for (Operation &op : getBody().front()) {
1731 if (!isa<VTableOp, VTableEntryOp>(op))
1733 "body may only contain 'moore.vtable' or 'moore.vtable_entry' ops");
1735 return mlir::success();
1739VTableEntryOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1740 Operation *self = getOperation();
1744 SymbolRefAttr target = getTargetAttr();
1746 symbolTable.lookupNearestSymbolFrom<func::FuncOp>(self, target);
1748 return emitOpError()
1749 <<
"cannot resolve target symbol to a function operation " << target;
1752 if (!isa<VTableOp>(self->getParentOp()))
1753 return emitOpError(
"must be nested directly inside a 'moore.vtable' op");
1755 Operation *currentOp = self;
1756 VTableOp currentVTable;
1757 bool defined =
false;
1764 while (
auto parentOp = dyn_cast<VTableOp>(currentOp->getParentOp())) {
1765 currentOp = parentOp;
1766 currentVTable = cast<VTableOp>(currentOp);
1768 auto classSymName = currentVTable.getSymName();
1769 ClassDeclOp parentClassDecl =
1770 symbolTable.lookupNearestSymbolFrom<ClassDeclOp>(
1771 parentOp, classSymName.getRootReference());
1772 assert(parentClassDecl &&
"VTableOp must point to a classdeclop");
1774 for (
auto method : parentClassDecl.getBody().getOps<ClassMethodDeclOp>()) {
1776 if (!method.getImpl())
1780 if (method.getSymName() ==
getName() && method.getImplAttr() == target)
1788 else if (method.getSymName() ==
getName() &&
1789 method.getImplAttr() != target && defined)
1790 return emitOpError() <<
"Target " << target
1791 <<
" should be overridden by " << classSymName;
1795 return emitOpError()
1796 <<
"Parent class does not point to any implementation!";
1801LogicalResult DynQueueExtractOp::verify() {
1802 auto elementType = cast<QueueType>(getInput().getType()).getElementType();
1806 if (getResult().getType() ==
elementType && getLowerIdx() != getUpperIdx()) {
1813LogicalResult QueueResizeOp::verify() {
1814 if (cast<QueueType>(getInput().getType()).getElementType() !=
1815 cast<QueueType>(getResult().getType()).getElementType())
1821LogicalResult QueueFromUnpackedArrayOp::verify() {
1823 auto queueElementType =
1824 cast<QueueType>(getResult().getType()).getElementType();
1826 auto arrayElementType =
1827 cast<UnpackedArrayType>(getInput().getType()).getElementType();
1829 if (queueElementType != arrayElementType) {
1830 return emitOpError()
1831 <<
"Queue element type doesn't match unpacked array element type";
1837LogicalResult QueueConcatOp::verify() {
1841 auto resultElType = cast<QueueType>(getResult().getType()).getElementType();
1843 for (Value input : getInputs()) {
1844 auto inpElType = cast<QueueType>(input.getType()).getElementType();
1845 if (inpElType != resultElType) {
1846 return emitOpError() <<
"Queue element type " << inpElType
1847 <<
" doesn't match result element type "
1855void DPIFuncOp::build(OpBuilder &odsBuilder, OperationState &odsState,
1856 StringAttr symName, ArrayRef<DPIArgInfo> dpiArgs,
1857 ArrayAttr argumentLocs, StringAttr verilogName) {
1858 auto *ctx = odsBuilder.getContext();
1859 odsState.addAttribute(getSymNameAttrName(odsState.name), symName);
1862 SmallVector<Type> inputTypes, resultTypes;
1863 SmallVector<Attribute> dirAttrs, nameAttrs;
1864 for (
auto &arg : dpiArgs) {
1865 dirAttrs.push_back(DPIArgDirectionAttr::get(ctx, arg.dir));
1866 nameAttrs.push_back(arg.name);
1868 inputTypes.push_back(arg.type);
1869 if (arg.dir == DPIArgDirection::Out || arg.dir == DPIArgDirection::InOut ||
1870 arg.dir == DPIArgDirection::Return)
1871 resultTypes.push_back(arg.type);
1874 odsState.addAttribute(
1875 getFunctionTypeAttrName(odsState.name),
1876 TypeAttr::get(FunctionType::get(ctx, inputTypes, resultTypes)));
1877 odsState.addAttribute(getDpiArgDirsAttrName(odsState.name),
1878 odsBuilder.getArrayAttr(dirAttrs));
1879 odsState.addAttribute(getDpiArgNamesAttrName(odsState.name),
1880 odsBuilder.getArrayAttr(nameAttrs));
1883 odsState.addAttribute(getArgumentLocsAttrName(odsState.name), argumentLocs);
1885 odsState.addAttribute(getVerilogNameAttrName(odsState.name), verilogName);
1886 odsState.addRegion();
1891 return llvm::StringSwitch<std::optional<DPIArgDirection>>(keyword)
1892 .Case(
"in", DPIArgDirection::In)
1893 .Case(
"out", DPIArgDirection::Out)
1894 .Case(
"inout", DPIArgDirection::InOut)
1895 .Case(
"return", DPIArgDirection::Return)
1896 .Default(std::nullopt);
1902 case DPIArgDirection::In:
1904 case DPIArgDirection::Out:
1906 case DPIArgDirection::InOut:
1908 case DPIArgDirection::Return:
1911 llvm_unreachable(
"unknown DPIArgDirection");
1914ParseResult DPIFuncOp::parse(OpAsmParser &parser, OperationState &result) {
1915 auto builder = parser.getBuilder();
1916 auto ctx = builder.getContext();
1918 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1920 StringAttr nameAttr;
1921 if (parser.parseSymbolName(nameAttr,
1922 DPIFuncOp::getSymNameAttrName(result.name),
1926 SmallVector<DPIArgDirection> argDirs;
1927 SmallVector<StringAttr> argNames;
1928 SmallVector<Type> argTypes;
1929 SmallVector<Attribute> argLocs;
1930 auto unknownLoc = builder.getUnknownLoc();
1931 bool hasLocs =
false;
1933 auto parseOneArg = [&]() -> ParseResult {
1934 StringRef dirKeyword;
1935 auto keyLoc = parser.getCurrentLocation();
1936 if (parser.parseKeyword(&dirKeyword))
1940 return parser.emitError(keyLoc,
1941 "expected DPI argument direction keyword");
1944 bool hasSSA = DPIFuncOp::isCallOperandDir(*dir);
1945 std::string argName;
1947 OpAsmParser::UnresolvedOperand ssaName;
1948 if (parser.parseOperand(ssaName,
false))
1950 argName = ssaName.name.substr(1).str();
1952 if (parser.parseKeywordOrString(&argName))
1957 if (parser.parseColonType(argType))
1960 argDirs.push_back(*dir);
1961 argNames.push_back(StringAttr::get(ctx, argName));
1962 argTypes.push_back(argType);
1964 std::optional<Location> maybeLoc;
1965 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1968 argLocs.push_back(*maybeLoc);
1971 argLocs.push_back(unknownLoc);
1976 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOneArg,
1977 " in DPI argument list"))
1981 SmallVector<Type> inputTypes, resultTypes;
1982 for (
auto [dir, type] :
llvm::zip(argDirs, argTypes)) {
1983 if (DPIFuncOp::isCallOperandDir(dir))
1984 inputTypes.push_back(type);
1985 if (dir == DPIArgDirection::Out || dir == DPIArgDirection::InOut ||
1986 dir == DPIArgDirection::Return)
1987 resultTypes.push_back(type);
1989 auto funcType = FunctionType::get(ctx, inputTypes, resultTypes);
1990 result.addAttribute(DPIFuncOp::getFunctionTypeAttrName(result.name),
1991 TypeAttr::get(funcType));
1994 SmallVector<Attribute> dirAttrs;
1995 for (
auto d : argDirs)
1996 dirAttrs.push_back(DPIArgDirectionAttr::
get(ctx,
d));
1997 result.addAttribute(DPIFuncOp::getDpiArgDirsAttrName(result.name),
1998 builder.getArrayAttr(dirAttrs));
2001 SmallVector<Attribute> nameAttrs(argNames.begin(), argNames.end());
2002 result.addAttribute(DPIFuncOp::getDpiArgNamesAttrName(result.name),
2003 builder.getArrayAttr(nameAttrs));
2006 result.addAttribute(DPIFuncOp::getArgumentLocsAttrName(result.name),
2007 builder.getArrayAttr(argLocs));
2010 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
2019::mlir::Type DPIFuncOp::cloneTypeWith(::mlir::TypeRange inputs,
2020 ::mlir::TypeRange results) {
2021 return FunctionType::get(getContext(), inputs, results);
2024void DPIFuncOp::getDPIArgTypes(SmallVectorImpl<Type> &argTypes) {
2025 auto funcType = getFunctionType();
2026 auto inputs = funcType.getInputs();
2027 auto results = funcType.getResults();
2028 auto dirs = getDpiArgDirsAttr();
2029 unsigned inputIdx = 0, resultIdx = 0;
2030 for (
auto dirAttr : dirs) {
2031 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2033 case DPIArgDirection::In:
2034 argTypes.push_back(inputs[inputIdx++]);
2036 case DPIArgDirection::Out:
2037 argTypes.push_back(results[resultIdx++]);
2039 case DPIArgDirection::InOut:
2040 argTypes.push_back(inputs[inputIdx++]);
2043 case DPIArgDirection::Return:
2044 argTypes.push_back(results[resultIdx++]);
2050LogicalResult DPIFuncOp::verify() {
2051 auto dirs = getDpiArgDirs();
2052 auto names = getDpiArgNames();
2053 if (dirs.size() != names.size())
2054 return emitOpError(
"argument directions and names must have the same size");
2057 bool seenReturn =
false;
2058 for (
auto [i, dirAttr] :
llvm::enumerate(dirs)) {
2059 auto dir = cast<DPIArgDirectionAttr>(dirAttr).getValue();
2060 if (dir == DPIArgDirection::Return) {
2062 return emitOpError(
"'return' argument must be the last argument");
2063 if (i != dirs.size() - 1)
2064 return emitOpError(
"'return' argument must be the last argument");
2071void DPIFuncOp::print(OpAsmPrinter &p) {
2074 StringRef visibilityAttrName =
2075 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2076 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
2077 p << visibility.getValue() <<
' ';
2078 p.printSymbolName(getSymName());
2080 auto dirs = getDpiArgDirs();
2081 auto names = getDpiArgNames();
2082 SmallVector<Type> argTypes;
2083 getDPIArgTypes(argTypes);
2086 llvm::interleaveComma(llvm::enumerate(dirs), p, [&](
auto it) {
2087 auto dir = cast<DPIArgDirectionAttr>(it.value()).getValue();
2088 auto i = it.index();
2089 auto name = cast<StringAttr>(names[i]).getValue();
2090 auto type = argTypes[i];
2096 p.printKeywordOrString(name);
2100 if (getArgumentLocs()) {
2101 auto loc = cast<Location>(getArgumentLocsAttr()[i]);
2102 if (loc != UnknownLoc::get(getContext()))
2103 p.printOptionalLocationSpecifier(loc);
2108 mlir::function_interface_impl::printFunctionAttributes(
2110 {visibilityAttrName, getFunctionTypeAttrName(), getDpiArgDirsAttrName(),
2111 getDpiArgNamesAttrName(), getArgumentLocsAttrName()});
2115FuncDPICallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2117 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr());
2119 return emitError(
"cannot find function declaration '")
2120 << getCallee() <<
"'";
2121 if (
auto dpiFunc = dyn_cast<DPIFuncOp>(referencedOp)) {
2122 auto funcType = cast<FunctionType>(dpiFunc.getFunctionType());
2123 auto expectedInputs = funcType.getInputs();
2124 auto expectedResults = funcType.getResults();
2125 if (getInputs().size() != expectedInputs.size())
2126 return emitError(
"expects ")
2127 << expectedInputs.size() <<
" DPI operands, but got "
2128 << getInputs().size();
2129 if (getResults().size() != expectedResults.size())
2130 return emitError(
"expects ")
2131 << expectedResults.size() <<
" DPI results, but got "
2132 << getResults().size();
2133 for (
auto [operand, expectedType] :
llvm::zip(getInputs(), expectedInputs))
2134 if (operand.getType() != expectedType)
2135 return emitError(
"operand type mismatch: expected ")
2136 << expectedType <<
", but got " << operand.getType();
2137 for (
auto [result, expectedType] :
llvm::zip(getResults(), expectedResults))
2138 if (result.getType() != expectedType)
2139 return emitError(
"result type mismatch: expected ")
2140 << expectedType <<
", but got " << result.getType();
2143 if (isa<func::FuncOp>(referencedOp))
2145 return emitError(
"callee must be 'moore.func.dpi' or 'func.func' but got '")
2146 << referencedOp->getName() <<
"'";
2149LogicalResult ReadMemBIOp::verify() {
2150 if (getFinishAddr() && !getStartAddr())
2151 return emitOpError(
"'finishAddr' requires 'startAddr' to be present");
2153 if (getSliceLeft() && !getSliceRight())
2154 return emitOpError(
"'sliceLeft' requires 'sliceRight' to be present");
2155 if (getSliceRight() && !getSliceLeft())
2156 return emitOpError(
"'sliceRight' requires 'sliceLeft' to be present");
2158 auto ref = dyn_cast<moore::RefType>(getDest().getType());
2160 return emitOpError(
"'dest' must be a Moore reference type, got ")
2161 << getDest().getType();
2163 unsigned numDims = 0;
2164 Type nested = ref.getNestedType();
2166 if (isa<moore::QueueType>(nested)) {
2169 while (
auto arr = dyn_cast<moore::UnpackedArrayType>(nested)) {
2171 nested = arr.getElementType();
2176 "'dest' must reference an unpacked array or queue, got ")
2177 << ref.getNestedType();
2179 if (getDimLows().size() != numDims || getDimDescending().size() != numDims)
2180 return emitOpError(
"'dimLows' and 'dimDescending' must have one entry per "
2181 "unpacked dimension");
2191#define GET_OP_CLASSES
2192#include "circt/Dialect/Moore/Moore.cpp.inc"
2193#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