18 #include "mlir/IR/Builders.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/TypeSwitch.h"
22 using namespace circt;
30 void SVModuleOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
31 llvm::StringRef name, hw::ModuleType type) {
32 state.addAttribute(SymbolTable::getSymbolAttrName(),
33 builder.getStringAttr(name));
34 state.addAttribute(getModuleTypeAttrName(state.name),
TypeAttr::get(type));
38 void SVModuleOp::print(OpAsmPrinter &p) {
42 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
43 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
44 p << visibility.getValue() <<
' ';
46 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
50 p.printRegion(getBodyRegion(),
false,
53 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
57 ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
59 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
63 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
68 SmallVector<hw::module_like_impl::PortParse> ports;
73 result.addAttribute(getModuleTypeAttrName(result.name), modType);
76 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
80 SmallVector<OpAsmParser::Argument, 4> entryArgs;
81 for (
auto &port : ports)
83 entryArgs.push_back(port);
86 auto &bodyRegion = *result.addRegion();
87 if (parser.parseRegion(bodyRegion, entryArgs))
90 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
94 void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
96 if (®ion != &getBodyRegion())
99 for (
auto [index, arg] : llvm::enumerate(region.front().getArguments()))
100 setNameFn(arg, moduleType.getInputNameAttr(index));
103 OutputOp SVModuleOp::getOutputOp() {
104 return cast<OutputOp>(getBody()->getTerminator());
107 OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
114 auto module = getParentOp();
117 auto outputTypes = module.getModuleType().getOutputTypes();
118 if (outputTypes.size() != getNumOperands())
119 return emitOpError(
"has ")
120 << getNumOperands() <<
" operands, but enclosing module @"
121 << module.getSymName() <<
" has " << outputTypes.size()
125 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
126 if (outputTypes[i] != getOperand(i).getType())
127 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
128 <<
") does not match output type (" << outputTypes[i]
129 <<
") of module @" << module.getSymName();
138 LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
141 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
143 return emitOpError(
"references unknown symbol @") << getModuleName();
146 auto module = dyn_cast<SVModuleOp>(symbol);
148 return emitOpError(
"must reference a 'moore.module', but @")
149 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
152 auto moduleType = module.getModuleType();
153 auto inputTypes = moduleType.getInputTypes();
155 if (inputTypes.size() != getNumOperands())
156 return emitOpError(
"has ")
157 << getNumOperands() <<
" operands, but target module @"
158 << module.getSymName() <<
" has " << inputTypes.size() <<
" inputs";
160 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
161 if (inputTypes[i] != getOperand(i).getType())
162 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
163 <<
") does not match input type (" << inputTypes[i]
164 <<
") of module @" << module.getSymName();
167 auto outputTypes = moduleType.getOutputTypes();
169 if (outputTypes.size() != getNumResults())
170 return emitOpError(
"has ")
171 << getNumOperands() <<
" results, but target module @"
172 << module.getSymName() <<
" has " << outputTypes.size()
175 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
176 if (outputTypes[i] != getResult(i).getType())
177 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
178 <<
") does not match output type (" << outputTypes[i]
179 <<
") of module @" << module.getSymName();
184 void InstanceOp::print(OpAsmPrinter &p) {
186 p.printAttributeWithoutType(getInstanceNameAttr());
188 p.printAttributeWithoutType(getModuleNameAttr());
194 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
197 ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
199 StringAttr instanceName;
200 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
204 FlatSymbolRefAttr moduleName;
205 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
209 auto loc = parser.getCurrentLocation();
210 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
211 SmallVector<Type> types;
215 if (parser.resolveOperands(inputs, types, loc, result.operands))
217 result.addAttribute(
"inputNames", names);
220 if (parser.parseArrow())
227 result.addAttribute(
"outputNames", names);
228 result.addTypes(types);
231 if (parser.parseOptionalAttrDict(result.attributes))
238 SmallString<32> name;
241 auto baseLen = name.size();
243 for (
auto [result, portName] :
244 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
245 if (!portName || portName.empty())
247 name.resize(baseLen);
248 name += portName.getValue();
249 setNameFn(result, name);
259 setNameFn(getResult(), *
getName());
263 PatternRewriter &rewriter) {
267 auto initial = op.getInitial();
268 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
269 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
270 rewriter.setInsertionPointAfter(op);
271 rewriter.create<BlockingAssignOp>(initial.getLoc(), op, initial);
278 auto *block = op->getBlock();
279 ContinuousAssignOp uniqueAssignOp;
280 for (
auto *user : op->getUsers()) {
282 if (user->getBlock() != block)
286 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
289 uniqueAssignOp = assignOp;
294 if (!isa<ReadOp>(user))
302 Value assignedValue = uniqueAssignOp.getSrc();
303 if (
auto name = op.getNameAttr(); name && !name.empty())
304 assignedValue = rewriter.create<AssignedVariableOp>(
305 op.getLoc(), name, uniqueAssignOp.getSrc());
308 rewriter.eraseOp(uniqueAssignOp);
309 for (
auto *user : llvm::make_early_inc_range(op->getUsers())) {
310 auto readOp = cast<ReadOp>(user);
311 rewriter.replaceOp(readOp, assignedValue);
315 rewriter.eraseOp(op);
319 SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
322 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
328 if (!isa<PackedType>(getType().getNestedType()))
331 return {MemorySlot{getResult(), getType().getNestedType()}};
334 Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
335 auto packedType = dyn_cast<PackedType>(slot.elemType);
338 auto bitWidth = packedType.getBitSize();
343 :
FVInt::getZero(*bitWidth);
344 Value value = builder.create<ConstantOp>(
345 getLoc(),
IntType::get(getContext(), *bitWidth, packedType.getDomain()),
347 if (value.getType() != packedType)
348 builder.create<ConversionOp>(getLoc(), packedType, value);
352 void VariableOp::handleBlockArgument(
const MemorySlot &slot,
353 BlockArgument argument,
354 OpBuilder &builder) {}
356 std::optional<mlir::PromotableAllocationOpInterface>
357 VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
358 OpBuilder &builder) {
359 if (defaultValue && defaultValue.use_empty())
360 defaultValue.getDefiningOp()->erase();
365 SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
366 if (isa<SVModuleOp>(getOperation()->getParentOp()))
371 auto refType = getType();
372 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
376 auto destructuredType = destructurable.getSubelementIndexMap();
377 if (!destructuredType)
380 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
383 DenseMap<Attribute, MemorySlot> VariableOp::destructure(
384 const DestructurableMemorySlot &slot,
385 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
386 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
387 assert(slot.ptr == getResult());
389 builder.setInsertionPointAfter(*
this);
391 auto destructurableType = cast<DestructurableTypeInterface>(getType());
392 DenseMap<Attribute, MemorySlot> slotMap;
393 for (Attribute index : usedIndices) {
394 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
395 assert(elemType &&
"used index must exist");
397 if (
auto name =
getName(); name && !name->empty())
399 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
401 builder.create<VariableOp>(getLoc(), elemType, varName, Value());
402 newAllocators.push_back(varOp);
403 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
409 std::optional<DestructurableAllocationOpInterface>
410 VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
411 OpBuilder &builder) {
412 assert(slot.ptr == getResult());
423 setNameFn(getResult(), *
getName());
427 bool modified =
false;
431 auto *block = op->getBlock();
432 ContinuousAssignOp uniqueAssignOp;
433 bool allUsesAreReads =
true;
434 for (
auto *user : op->getUsers()) {
436 if (user->getBlock() != block)
440 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
443 uniqueAssignOp = assignOp;
448 if (!isa<ReadOp>(user))
449 allUsesAreReads =
false;
454 if (uniqueAssignOp && !op.getAssignment()) {
455 rewriter.modifyOpInPlace(
456 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
457 rewriter.eraseOp(uniqueAssignOp);
465 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
468 auto assignedValue = op.getAssignment();
469 if (
auto name = op.getNameAttr(); name && !name.empty())
471 rewriter.create<AssignedVariableOp>(op.getLoc(), name, assignedValue);
475 for (
auto *user : llvm::make_early_inc_range(op->getUsers())) {
476 auto readOp = cast<ReadOp>(user);
477 rewriter.replaceOp(readOp, assignedValue);
479 rewriter.eraseOp(op);
483 return success(modified);
492 setNameFn(getResult(), *
getName());
496 PatternRewriter &rewriter) {
499 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
500 if (otherOp.getNameAttr() == op.getNameAttr()) {
501 rewriter.replaceOp(op, otherOp);
507 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
509 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
510 auto moduleType = moduleOp.getModuleType();
511 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
512 if (portName == op.getNameAttr()) {
513 rewriter.replaceOp(op, blockArg);
520 for (
auto &use : op->getUses()) {
521 auto *useOwner = use.getOwner();
522 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
523 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
524 auto moduleType = moduleOp.getModuleType();
525 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
526 if (portName == op.getNameAttr()) {
527 rewriter.replaceOp(op, op.getInput());
542 void ConstantOp::print(OpAsmPrinter &p) {
545 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
547 p.printStrippedAttrOrType(getType());
550 ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
553 auto valueLoc = parser.getCurrentLocation();
558 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
563 if (parser.parseCustomTypeWithFallback(type))
571 value = value.
sext(type.getWidth());
572 }
else if (type.getWidth() < value.
getBitWidth()) {
575 unsigned neededBits =
577 if (type.getWidth() < neededBits)
578 return parser.emitError(valueLoc)
579 <<
"value requires " << neededBits
580 <<
" bits, but result type only has " << type.getWidth();
581 value = value.
trunc(type.getWidth());
587 return parser.emitError(valueLoc)
588 <<
"value contains X or Z bits, but result type " << type
589 <<
" only allows two-valued bits";
593 result.addAttribute(
"value", attrValue);
594 result.addTypes(type);
599 auto attrWidth = getValue().getBitWidth();
600 auto typeWidth = getType().getWidth();
601 if (attrWidth != typeWidth)
602 return emitError(
"attribute width ")
603 << attrWidth <<
" does not match return type's width " << typeWidth;
607 void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
608 const FVInt &value) {
610 "FVInt width must match type width");
614 void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
615 const APInt &value) {
616 assert(type.getWidth() == value.getBitWidth() &&
617 "APInt width must match type width");
618 build(builder, result, type,
FVInt(value));
625 void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
627 build(builder, result, type,
628 APInt(type.getWidth(), (uint64_t)value,
true));
631 OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
632 assert(adaptor.getOperands().empty() &&
"constant has no operands");
633 return getValueAttr();
640 LogicalResult ConcatOp::inferReturnTypes(
641 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
642 DictionaryAttr attrs, mlir::OpaqueProperties properties,
643 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
646 for (
auto operand : operands) {
647 auto type = cast<IntType>(operand.getType());
650 width += type.getWidth();
652 results.push_back(
IntType::get(context, width, domain));
660 LogicalResult ConcatRefOp::inferReturnTypes(
661 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
662 DictionaryAttr attrs, mlir::OpaqueProperties properties,
663 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
666 for (
auto operand : operands) {
667 auto type = cast<IntType>(cast<RefType>(operand.getType()).getNestedType());
670 width += type.getWidth();
681 if (
auto arrayType = dyn_cast<ArrayType>(type))
682 return {arrayType.getSize(), arrayType.getElementType()};
683 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
684 return {arrayType.getSize(), arrayType.getElementType()};
685 assert(0 &&
"expected ArrayType or UnpackedArrayType");
693 if (getElements().size() != size)
694 return emitOpError() <<
"has " << getElements().size()
695 <<
" operands, but result type requires " << size;
701 auto value = getElements()[0];
703 return emitOpError() <<
"operands have type " << value.getType()
714 if (
auto structType = dyn_cast<StructType>(type))
715 return structType.getFieldIndex(name);
716 if (
auto structType = dyn_cast<UnpackedStructType>(type))
717 return structType.getFieldIndex(name);
718 assert(0 &&
"expected StructType or UnpackedStructType");
723 if (
auto structType = dyn_cast<StructType>(type))
724 return structType.getMembers();
725 if (
auto structType = dyn_cast<UnpackedStructType>(type))
726 return structType.getMembers();
727 assert(0 &&
"expected StructType or UnpackedStructType");
741 if (getFields().size() != members.size())
742 return emitOpError() <<
"has " << getFields().size()
743 <<
" operands, but result type requires "
747 for (
auto [index, pair] : llvm::enumerate(llvm::zip(getFields(), members))) {
748 auto [value, member] = pair;
749 if (value.getType() != member.type)
750 return emitOpError() <<
"operand #" << index <<
" has type "
751 << value.getType() <<
", but struct field "
752 << member.name <<
" requires " << member.type;
757 OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
758 SmallVector<NamedAttribute> fields;
759 for (
auto [member, field] :
763 fields.push_back(NamedAttribute(member.name, field));
775 return emitOpError() <<
"extracts field " << getFieldNameAttr()
776 <<
" which does not exist in " << getInput().getType();
777 if (type != getType())
778 return emitOpError() <<
"result type " << getType()
779 <<
" must match struct field type " << type;
783 OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
785 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
786 if (
auto value = fields.get(getFieldNameAttr()))
790 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
791 if (inject.getFieldNameAttr() == getFieldNameAttr())
792 return inject.getNewValue();
797 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
799 return create.getFields()[*index];
812 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
814 return emitOpError() <<
"extracts field " << getFieldNameAttr()
815 <<
" which does not exist in " << getInput().getType();
816 if (type != getType().getNestedType())
817 return emitOpError() <<
"result ref of type " << getType().getNestedType()
818 <<
" must match struct field type " << type;
822 bool StructExtractRefOp::canRewire(
823 const DestructurableMemorySlot &slot,
824 SmallPtrSetImpl<Attribute> &usedIndices,
825 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
826 const DataLayout &dataLayout) {
827 if (slot.ptr != getInput())
829 auto index = getFieldNameAttr();
830 if (!index || !slot.subelementTypes.contains(index))
832 usedIndices.insert(index);
837 StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
838 DenseMap<Attribute, MemorySlot> &subslots,
839 OpBuilder &builder,
const DataLayout &dataLayout) {
840 auto index = getFieldNameAttr();
841 const MemorySlot &memorySlot = subslots.at(index);
842 replaceAllUsesWith(memorySlot.ptr);
843 getInputMutable().drop();
845 return DeletionKind::Keep;
855 return emitOpError() <<
"injects field " << getFieldNameAttr()
856 <<
" which does not exist in " << getInput().getType();
857 if (type != getNewValue().getType())
858 return emitOpError() <<
"injected value " << getNewValue().getType()
859 <<
" must match struct field type " << type;
863 OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
864 auto input = adaptor.getInput();
865 auto newValue = adaptor.getNewValue();
866 if (!input || !newValue)
868 NamedAttrList fields(cast<DictionaryAttr>(input));
869 fields.set(getFieldNameAttr(), newValue);
870 return fields.getDictionary(getContext());
874 PatternRewriter &rewriter) {
879 SmallPtrSet<Operation *, 4> injectOps;
880 DenseMap<StringAttr, Value> fieldValues;
882 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
883 if (!injectOps.insert(injectOp).second)
885 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
886 input = injectOp.getInput();
888 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
889 for (
auto [value, member] : llvm::zip(createOp.getFields(), members))
890 fieldValues.insert({member.name, value});
893 if (fieldValues.size() == members.size()) {
894 SmallVector<Value> values;
895 values.reserve(fieldValues.size());
896 for (
auto member : members)
897 values.push_back(fieldValues.lookup(member.name));
898 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
904 if (injectOps.size() == fieldValues.size())
909 for (
auto member : members)
910 if (
auto value = fieldValues.lookup(member.name))
911 input = rewriter.create<StructInjectOp>(op.getLoc(), op.getType(), input,
913 rewriter.replaceOp(op, input);
924 return TypeSwitch<Type, LogicalResult>(getType())
925 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
926 auto members = type.getMembers();
927 auto resultType = getType();
929 for (
const auto &member : members)
930 if (member.name == fieldName && member.type == resultType)
932 emitOpError(
"input type must match the union field type");
935 .Default([
this](
auto &) {
936 emitOpError(
"input type must be UnionType or UnpackedUnionType");
948 return TypeSwitch<Type, LogicalResult>(getInput().getType())
949 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
950 auto members = type.getMembers();
952 auto resultType = getType();
953 for (
const auto &member : members)
954 if (member.name == fieldName && member.type == resultType)
956 emitOpError(
"result type must match the union field type");
959 .Default([
this](
auto &) {
960 emitOpError(
"input type must be UnionType or UnpackedUnionType");
972 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
973 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
974 auto members = type.getMembers();
976 auto resultType = getType().getNestedType();
977 for (
const auto &member : members)
978 if (member.name == fieldName && member.type == resultType)
980 emitOpError(
"result type must match the union field type");
983 .Default([
this](
auto &) {
984 emitOpError(
"input type must be UnionType or UnpackedUnionType");
995 auto cond = dyn_cast<ConditionalOp>(*(*this).getParentOp());
997 emitOpError(
"must have a conditional parent");
1002 auto condType = cond.getType();
1003 auto yieldType = getOperand().getType();
1004 if (condType != yieldType) {
1005 emitOpError(
"yield type must match conditional. Expected ")
1006 << condType <<
", but got " << yieldType <<
".";
1017 OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1019 if (getInput().getType() == getResult().getType())
1023 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1024 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1025 auto toIntType = dyn_cast<IntType>(getResult().getType());
1026 if (intInput && fromIntType && toIntType &&
1027 fromIntType.getWidth() == toIntType.getWidth()) {
1045 OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1047 if (getInput().getType() == getResult().getType())
1056 bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1058 bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1059 return getDst() == slot.ptr;
1062 Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1064 const DataLayout &dataLayout) {
1068 bool BlockingAssignOp::canUsesBeRemoved(
1069 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1070 SmallVectorImpl<OpOperand *> &newBlockingUses,
1071 const DataLayout &dataLayout) {
1073 if (blockingUses.size() != 1)
1075 Value blockingUse = (*blockingUses.begin())->
get();
1076 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1077 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1080 DeletionKind BlockingAssignOp::removeBlockingUses(
1081 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1082 OpBuilder &builder, Value reachingDefinition,
1083 const DataLayout &dataLayout) {
1084 return DeletionKind::Delete;
1091 bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1092 return getInput() == slot.ptr;
1095 bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1097 Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1098 Value reachingDef,
const DataLayout &dataLayout) {
1099 llvm_unreachable(
"getStored should not be called on ReadOp");
1102 bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1103 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1104 SmallVectorImpl<OpOperand *> &newBlockingUses,
1105 const DataLayout &dataLayout) {
1107 if (blockingUses.size() != 1)
1109 Value blockingUse = (*blockingUses.begin())->
get();
1110 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1111 getResult().getType() == slot.elemType;
1115 ReadOp::removeBlockingUses(
const MemorySlot &slot,
1116 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1117 OpBuilder &builder, Value reachingDefinition,
1118 const DataLayout &dataLayout) {
1119 getResult().replaceAllUsesWith(reachingDefinition);
1120 return DeletionKind::Delete;
1129 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1130 if (lhsValue && lhsValue.getValue() == 1)
1133 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1134 if (rhsValue && rhsValue.getValue().isZero())
1136 FVInt(rhsValue.getValue().getBitWidth(), 1));
1141 OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1146 Location loc = op.getLoc();
1147 auto intType = cast<IntType>(op.getRhs().getType());
1148 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1149 if (baseOp.getValue() == 2) {
1150 Value constOne = rewriter.create<ConstantOp>(loc, intType, 1);
1151 Value constZero = rewriter.create<ConstantOp>(loc, intType, 0);
1152 Value shift = rewriter.create<ShlOp>(loc, constOne, op.getRhs());
1153 Value isNegative = rewriter.create<SltOp>(loc, op.getRhs(), constZero);
1154 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1155 op, op.getLhs().getType(), isNegative);
1156 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1157 rewriter.setInsertionPointToStart(thenBlock);
1158 rewriter.create<YieldOp>(loc, constZero);
1159 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1160 rewriter.setInsertionPointToStart(elseBlock);
1161 rewriter.create<YieldOp>(loc, shift);
1173 OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1178 Location loc = op.getLoc();
1179 auto intType = cast<IntType>(op.getRhs().getType());
1180 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1181 if (baseOp.getValue() == 2) {
1182 Value constOne = rewriter.create<ConstantOp>(loc, intType, 1);
1183 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1196 #define GET_OP_CLASSES
1197 #include "circt/Dialect/Moore/Moore.cpp.inc"
1198 #include "circt/Dialect/Moore/MooreEnums.cpp.inc"
assert(baseType &&"element must be base type")
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static InstancePath empty
static ArrayRef< StructLikeMember > getStructMembers(Type type)
static std::optional< uint32_t > getStructFieldIndex(Type type, StringAttr name)
static OpFoldResult powCommonFolding(MLIRContext *ctxt, Attribute lhs, Attribute rhs)
static std::pair< unsigned, UnpackedType > getArrayElements(Type type)
static UnpackedType getStructFieldType(Type type, StringAttr name)
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.
An unpacked SystemVerilog type.
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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.
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
void printModuleSignatureNew(OpAsmPrinter &p, Region &body, hw::ModuleType modType, ArrayRef< Attribute > portAttrs, ArrayRef< Location > locAttrs)
FunctionType getModuleType(Operation *module)
Return the signature for the specified module as a function type.
Domain
The number of values each bit of a type can assume.
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
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