18#include "mlir/IR/Builders.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/TypeSwitch.h"
30void 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));
38void 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(),
57ParseResult 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);
94void 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));
103OutputOp SVModuleOp::getOutputOp() {
104 return cast<OutputOp>(getBody()->getTerminator());
107OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
113LogicalResult OutputOp::verify() {
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();
138LogicalResult 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();
184void InstanceOp::print(OpAsmPrinter &p) {
186 p.printAttributeWithoutType(getInstanceNameAttr());
188 p.printAttributeWithoutType(getModuleNameAttr());
194 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
197ParseResult 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());
262LogicalResult VariableOp::canonicalize(VariableOp op,
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);
319SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
322 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
328 if (!isa<PackedType>(getType().getNestedType()))
331 return {MemorySlot{getResult(), getType().getNestedType()}};
334Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
335 auto packedType = dyn_cast<PackedType>(slot.elemType);
338 auto bitWidth = packedType.getBitSize();
341 auto fvint = packedType.getDomain() == Domain::FourValued
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);
352void VariableOp::handleBlockArgument(
const MemorySlot &slot,
353 BlockArgument argument,
354 OpBuilder &builder) {}
356std::optional<mlir::PromotableAllocationOpInterface>
357VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
358 OpBuilder &builder) {
359 if (defaultValue && defaultValue.use_empty())
360 defaultValue.getDefiningOp()->erase();
365SmallVector<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}};
383DenseMap<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())
398 varName = StringAttr::get(
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});
409std::optional<DestructurableAllocationOpInterface>
410VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
411 OpBuilder &builder) {
412 assert(slot.ptr == getResult());
423 setNameFn(getResult(), *
getName());
426LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
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());
495LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
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());
542void ConstantOp::print(OpAsmPrinter &p) {
545 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
547 p.printStrippedAttrOrType(getType());
550ParseResult 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());
586 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
587 return parser.emitError(valueLoc)
588 <<
"value contains X or Z bits, but result type " << type
589 <<
" only allows two-valued bits";
592 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
593 result.addAttribute(
"value", attrValue);
594 result.addTypes(type);
598LogicalResult ConstantOp::verify() {
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;
607void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
608 const FVInt &value) {
610 "FVInt width must match type width");
611 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
614void 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));
625void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
627 build(builder, result, type,
628 APInt(type.getWidth(), (uint64_t)value,
true));
631OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
632 assert(adaptor.getOperands().empty() &&
"constant has no operands");
633 return getValueAttr();
640LogicalResult ConcatOp::inferReturnTypes(
641 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
642 DictionaryAttr attrs, mlir::OpaqueProperties properties,
643 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
644 Domain domain = Domain::TwoValued;
646 for (
auto operand : operands) {
647 auto type = cast<IntType>(operand.getType());
648 if (type.getDomain() == Domain::FourValued)
649 domain = Domain::FourValued;
650 width += type.getWidth();
652 results.push_back(IntType::get(context, width, domain));
660LogicalResult ConcatRefOp::inferReturnTypes(
661 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
662 DictionaryAttr attrs, mlir::OpaqueProperties properties,
663 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
664 Domain domain = Domain::TwoValued;
666 for (
auto operand : operands) {
667 auto type = cast<IntType>(cast<RefType>(operand.getType()).getNestedType());
668 if (type.getDomain() == Domain::FourValued)
669 domain = Domain::FourValued;
670 width += type.getWidth();
672 results.push_back(RefType::get(IntType::get(context, width, domain)));
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");
689LogicalResult ArrayCreateOp::verify() {
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");
737LogicalResult StructCreateOp::verify() {
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;
757OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
758 SmallVector<NamedAttribute> fields;
759 for (
auto [member, field] :
763 fields.push_back(NamedAttribute(member.name, field));
765 return DictionaryAttr::get(getContext(), fields);
772LogicalResult StructExtractOp::verify() {
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;
783OpFoldResult 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];
810LogicalResult StructExtractRefOp::verify() {
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;
822bool 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);
837StructExtractRefOp::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;
852LogicalResult StructInjectOp::verify() {
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;
863OpFoldResult 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());
873LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
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);
921LogicalResult UnionCreateOp::verify() {
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");
945LogicalResult UnionExtractOp::verify() {
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");
969LogicalResult UnionExtractRefOp::verify() {
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");
993LogicalResult YieldOp::verify() {
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 <<
".";
1017OpFoldResult 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()) {
1030 if (toIntType.getDomain() == Domain::FourValued)
1035 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1045OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1047 if (getInput().getType() == getResult().getType())
1056bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1058bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1059 return getDst() == slot.ptr;
1062Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1064 const DataLayout &dataLayout) {
1068bool 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;
1080DeletionKind BlockingAssignOp::removeBlockingUses(
1081 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1082 OpBuilder &builder, Value reachingDefinition,
1083 const DataLayout &dataLayout) {
1084 return DeletionKind::Delete;
1091bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1092 return getInput() == slot.ptr;
1095bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1097Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1098 Value reachingDef,
const DataLayout &dataLayout) {
1099 llvm_unreachable(
"getStored should not be called on ReadOp");
1102bool 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;
1115ReadOp::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())
1135 return FVIntegerAttr::get(ctxt,
1136 FVInt(rhsValue.getValue().getBitWidth(), 1));
1141OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1145LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
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);
1173OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1177LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
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());
1195OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1196 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1197 if (intAttr.getValue().isZero())
1208#define GET_OP_CLASSES
1209#include "circt/Dialect/Moore/Moore.cpp.inc"
1210#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 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)
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.
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.
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