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::OpaqueProperties 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::OpaqueProperties 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::OpaqueProperties 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 "
1887#define GET_OP_CLASSES
1888#include "circt/Dialect/Moore/Moore.cpp.inc"
1889#include "circt/Dialect/Moore/MooreEnums.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static Location getLoc(DefSlot slot)
static OpFoldResult powCommonFolding(MLIRContext *ctxt, Attribute lhs, Attribute rhs)
static ArrayRef< StructLikeMember > getStructMembers(Type type)
static std::optional< uint32_t > getStructFieldIndex(Type type, StringAttr name)
static UnpackedType getStructFieldType(Type type, StringAttr name)
static std::pair< unsigned, UnpackedType > getArrayElements(Type type)
static InstancePath empty
Four-valued arbitrary precision integers.
bool isNegative() const
Determine whether the integer interpreted as a signed number would be negative.
FVInt sext(unsigned bitWidth) const
Sign-extend the integer to a new bit width.
unsigned getSignificantBits() const
Compute the minimum bit width necessary to accurately represent this integer's value and sign.
static FVInt getAllX(unsigned numBits)
Construct an FVInt with all bits set to X.
bool hasUnknown() const
Determine if any bits are X or Z.
unsigned getActiveBits() const
Compute the number of active bits in the value.
unsigned getBitWidth() const
Return the number of bits this integer has.
FVInt trunc(unsigned bitWidth) const
Truncate the integer to a smaller bit width.
A packed SystemVerilog type.
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Domain getDomain() const
Get the value domain of this type.
An unpacked SystemVerilog type.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction
The direction of a Component or Cell port.
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
void printModuleSignatureNew(OpAsmPrinter &p, Region &body, hw::ModuleType modType, ArrayRef< Attribute > portAttrs, ArrayRef< Location > locAttrs)
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function type.
Domain
The number of values each bit of a type can assume.
RealWidth
The type of floating point / real number behind a RealType.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ParseResult parseInputPortList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inputs, SmallVectorImpl< Type > &inputTypes, ArrayAttr &inputNames)
Parse a list of instance input ports.
void printOutputPortList(OpAsmPrinter &p, Operation *op, TypeRange resultTypes, ArrayAttr resultNames)
Print a list of instance output ports.
void printFVInt(AsmPrinter &p, const FVInt &value)
Print a four-valued integer usign an AsmPrinter.
ParseResult parseFVInt(AsmParser &p, FVInt &result)
Parse a four-valued integer using an AsmParser.
void printInputPortList(OpAsmPrinter &p, Operation *op, OperandRange inputs, TypeRange inputTypes, ArrayAttr inputNames)
Print a list of instance input ports.
ParseResult parseOutputPortList(OpAsmParser &parser, SmallVectorImpl< Type > &resultTypes, ArrayAttr &resultNames)
Parse a list of instance output ports.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn