18#include "mlir/IR/Builders.h"
19#include "llvm/ADT/APSInt.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/TypeSwitch.h"
31void SVModuleOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
32 llvm::StringRef name, hw::ModuleType type) {
33 state.addAttribute(SymbolTable::getSymbolAttrName(),
34 builder.getStringAttr(name));
35 state.addAttribute(getModuleTypeAttrName(state.name), TypeAttr::get(type));
39void SVModuleOp::print(OpAsmPrinter &p) {
43 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
44 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
45 p << visibility.getValue() <<
' ';
47 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
51 p.printRegion(getBodyRegion(),
false,
54 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
58ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
60 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
64 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
69 SmallVector<hw::module_like_impl::PortParse> ports;
74 result.addAttribute(getModuleTypeAttrName(result.name), modType);
77 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
81 SmallVector<OpAsmParser::Argument, 4> entryArgs;
82 for (
auto &port : ports)
84 entryArgs.push_back(port);
87 auto &bodyRegion = *result.addRegion();
88 if (parser.parseRegion(bodyRegion, entryArgs))
91 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
95void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
97 if (®ion != &getBodyRegion())
100 for (
auto [index, arg] :
llvm::enumerate(region.front().getArguments()))
101 setNameFn(arg, moduleType.getInputNameAttr(index));
104OutputOp SVModuleOp::getOutputOp() {
105 return cast<OutputOp>(getBody()->getTerminator());
108OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
114LogicalResult OutputOp::verify() {
115 auto module = getParentOp();
118 auto outputTypes =
module.getModuleType().getOutputTypes();
119 if (outputTypes.size() != getNumOperands())
120 return emitOpError(
"has ")
121 << getNumOperands() <<
" operands, but enclosing module @"
122 <<
module.getSymName() << " has " << outputTypes.size()
126 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
127 if (outputTypes[i] != getOperand(i).getType())
128 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
129 <<
") does not match output type (" << outputTypes[i]
130 <<
") of module @" <<
module.getSymName();
139LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
142 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
144 return emitOpError(
"references unknown symbol @") << getModuleName();
147 auto module = dyn_cast<SVModuleOp>(symbol);
149 return emitOpError(
"must reference a 'moore.module', but @")
150 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
153 auto moduleType =
module.getModuleType();
154 auto inputTypes = moduleType.getInputTypes();
156 if (inputTypes.size() != getNumOperands())
157 return emitOpError(
"has ")
158 << getNumOperands() <<
" operands, but target module @"
159 <<
module.getSymName() << " has " << inputTypes.size() << " inputs";
161 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
162 if (inputTypes[i] != getOperand(i).getType())
163 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
164 <<
") does not match input type (" << inputTypes[i]
165 <<
") of module @" <<
module.getSymName();
168 auto outputTypes = moduleType.getOutputTypes();
170 if (outputTypes.size() != getNumResults())
171 return emitOpError(
"has ")
172 << getNumOperands() <<
" results, but target module @"
173 <<
module.getSymName() << " has " << outputTypes.size()
176 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
177 if (outputTypes[i] != getResult(i).getType())
178 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
179 <<
") does not match output type (" << outputTypes[i]
180 <<
") of module @" <<
module.getSymName();
185void InstanceOp::print(OpAsmPrinter &p) {
187 p.printAttributeWithoutType(getInstanceNameAttr());
189 p.printAttributeWithoutType(getModuleNameAttr());
195 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
198ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
200 StringAttr instanceName;
201 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
205 FlatSymbolRefAttr moduleName;
206 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
210 auto loc = parser.getCurrentLocation();
211 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
212 SmallVector<Type> types;
216 if (parser.resolveOperands(inputs, types, loc, result.operands))
218 result.addAttribute(
"inputNames", names);
221 if (parser.parseArrow())
228 result.addAttribute(
"outputNames", names);
229 result.addTypes(types);
232 if (parser.parseOptionalAttrDict(result.attributes))
239 SmallString<32> name;
242 auto baseLen = name.size();
244 for (
auto [result, portName] :
245 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
246 if (!portName || portName.empty())
248 name.resize(baseLen);
249 name += portName.getValue();
250 setNameFn(result, name);
260 setNameFn(getResult(), *
getName());
263LogicalResult VariableOp::canonicalize(VariableOp op,
264 PatternRewriter &rewriter) {
268 auto initial = op.getInitial();
269 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
270 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
271 rewriter.setInsertionPointAfter(op);
272 BlockingAssignOp::create(rewriter, initial.getLoc(), op, initial);
279 auto *block = op->getBlock();
280 ContinuousAssignOp uniqueAssignOp;
281 for (
auto *user : op->getUsers()) {
283 if (user->getBlock() != block)
287 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
290 uniqueAssignOp = assignOp;
295 if (!isa<ReadOp>(user))
303 Value assignedValue = uniqueAssignOp.getSrc();
304 if (
auto name = op.getNameAttr(); name && !name.empty())
305 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
306 uniqueAssignOp.getSrc());
309 rewriter.eraseOp(uniqueAssignOp);
310 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
311 auto readOp = cast<ReadOp>(user);
312 rewriter.replaceOp(readOp, assignedValue);
316 rewriter.eraseOp(op);
320SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
323 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
329 if (!isa<PackedType>(getType().getNestedType()))
332 return {MemorySlot{getResult(), getType().getNestedType()}};
335Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
336 auto packedType = dyn_cast<PackedType>(slot.elemType);
339 auto bitWidth = packedType.getBitSize();
342 auto fvint = packedType.getDomain() == Domain::FourValued
344 :
FVInt::getZero(*bitWidth);
345 Value value = ConstantOp::create(
347 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
348 if (value.getType() != packedType)
349 ConversionOp::create(builder,
getLoc(), packedType, value);
353void VariableOp::handleBlockArgument(
const MemorySlot &slot,
354 BlockArgument argument,
355 OpBuilder &builder) {}
357std::optional<mlir::PromotableAllocationOpInterface>
358VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
359 OpBuilder &builder) {
360 if (defaultValue && defaultValue.use_empty())
361 defaultValue.getDefiningOp()->erase();
366SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
367 if (isa<SVModuleOp>(getOperation()->getParentOp()))
372 auto refType = getType();
373 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
377 auto destructuredType = destructurable.getSubelementIndexMap();
378 if (!destructuredType)
381 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
384DenseMap<Attribute, MemorySlot> VariableOp::destructure(
385 const DestructurableMemorySlot &slot,
386 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
387 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
388 assert(slot.ptr == getResult());
390 builder.setInsertionPointAfter(*
this);
392 auto destructurableType = cast<DestructurableTypeInterface>(getType());
393 DenseMap<Attribute, MemorySlot> slotMap;
394 for (Attribute index : usedIndices) {
395 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
396 assert(elemType &&
"used index must exist");
398 if (
auto name =
getName(); name && !name->empty())
399 varName = StringAttr::get(
400 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
402 VariableOp::create(builder,
getLoc(), elemType, varName, Value());
403 newAllocators.push_back(varOp);
404 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
410std::optional<DestructurableAllocationOpInterface>
411VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
412 OpBuilder &builder) {
413 assert(slot.ptr == getResult());
424 setNameFn(getResult(), *
getName());
427LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
428 bool modified =
false;
432 auto *block = op->getBlock();
433 ContinuousAssignOp uniqueAssignOp;
434 bool allUsesAreReads =
true;
435 for (
auto *user : op->getUsers()) {
437 if (user->getBlock() != block)
441 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
444 uniqueAssignOp = assignOp;
449 if (!isa<ReadOp>(user))
450 allUsesAreReads =
false;
455 if (uniqueAssignOp && !op.getAssignment()) {
456 rewriter.modifyOpInPlace(
457 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
458 rewriter.eraseOp(uniqueAssignOp);
466 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
469 auto assignedValue = op.getAssignment();
470 if (
auto name = op.getNameAttr(); name && !name.empty())
471 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
476 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
477 auto readOp = cast<ReadOp>(user);
478 rewriter.replaceOp(readOp, assignedValue);
480 rewriter.eraseOp(op);
484 return success(modified);
493 setNameFn(getResult(), *
getName());
496LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
497 PatternRewriter &rewriter) {
500 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
501 if (otherOp.getNameAttr() == op.getNameAttr()) {
502 rewriter.replaceOp(op, otherOp);
508 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
510 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
511 auto moduleType = moduleOp.getModuleType();
512 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
513 if (portName == op.getNameAttr()) {
514 rewriter.replaceOp(op, blockArg);
521 for (
auto &use : op->getUses()) {
522 auto *useOwner = use.getOwner();
523 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
524 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
525 auto moduleType = moduleOp.getModuleType();
526 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
527 if (portName == op.getNameAttr()) {
528 rewriter.replaceOp(op, op.getInput());
543void ConstantOp::print(OpAsmPrinter &p) {
546 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
548 p.printStrippedAttrOrType(getType());
551ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
554 auto valueLoc = parser.getCurrentLocation();
559 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
564 if (parser.parseCustomTypeWithFallback(type))
572 value = value.
sext(type.getWidth());
573 }
else if (type.getWidth() < value.
getBitWidth()) {
576 unsigned neededBits =
578 if (type.getWidth() < neededBits)
579 return parser.emitError(valueLoc)
580 <<
"value requires " << neededBits
581 <<
" bits, but result type only has " << type.getWidth();
582 value = value.
trunc(type.getWidth());
587 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
588 return parser.emitError(valueLoc)
589 <<
"value contains X or Z bits, but result type " << type
590 <<
" only allows two-valued bits";
593 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
594 result.addAttribute(
"value", attrValue);
595 result.addTypes(type);
599LogicalResult ConstantOp::verify() {
600 auto attrWidth = getValue().getBitWidth();
601 auto typeWidth = getType().getWidth();
602 if (attrWidth != typeWidth)
603 return emitError(
"attribute width ")
604 << attrWidth <<
" does not match return type's width " << typeWidth;
608void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
609 const FVInt &value) {
611 "FVInt width must match type width");
612 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
615void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
616 const APInt &value) {
617 assert(type.getWidth() == value.getBitWidth() &&
618 "APInt width must match type width");
619 build(builder, result, type,
FVInt(value));
626void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
627 int64_t value,
bool isSigned) {
628 build(builder, result, type,
629 APInt(type.getWidth(), (uint64_t)value, isSigned));
632OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
633 assert(adaptor.getOperands().empty() &&
"constant has no operands");
634 return getValueAttr();
641OpFoldResult ConstantTimeOp::fold(FoldAdaptor adaptor) {
642 return getValueAttr();
649LogicalResult ConcatOp::inferReturnTypes(
650 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
651 DictionaryAttr attrs, mlir::OpaqueProperties properties,
652 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
653 Domain domain = Domain::TwoValued;
655 for (
auto operand : operands) {
656 auto type = cast<IntType>(operand.getType());
657 if (type.getDomain() == Domain::FourValued)
658 domain = Domain::FourValued;
659 width += type.getWidth();
661 results.push_back(IntType::get(context, width, domain));
669LogicalResult ConcatRefOp::inferReturnTypes(
670 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
671 DictionaryAttr attrs, mlir::OpaqueProperties properties,
672 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
673 Domain domain = Domain::TwoValued;
675 for (Value operand : operands) {
676 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
677 PackedType packedType = dyn_cast<PackedType>(nestedType);
683 if (packedType.
getDomain() == Domain::FourValued)
684 domain = Domain::FourValued;
687 std::optional<int> bitSize = packedType.
getBitSize();
693 results.push_back(RefType::get(IntType::get(context, width, domain)));
702 if (
auto arrayType = dyn_cast<ArrayType>(type))
703 return {arrayType.getSize(), arrayType.getElementType()};
704 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
705 return {arrayType.getSize(), arrayType.getElementType()};
706 assert(0 &&
"expected ArrayType or UnpackedArrayType");
710LogicalResult ArrayCreateOp::verify() {
714 if (getElements().size() != size)
715 return emitOpError() <<
"has " << getElements().size()
716 <<
" operands, but result type requires " << size;
722 auto value = getElements()[0];
724 return emitOpError() <<
"operands have type " << value.getType()
735 if (
auto structType = dyn_cast<StructType>(type))
736 return structType.getFieldIndex(name);
737 if (
auto structType = dyn_cast<UnpackedStructType>(type))
738 return structType.getFieldIndex(name);
739 assert(0 &&
"expected StructType or UnpackedStructType");
744 if (
auto structType = dyn_cast<StructType>(type))
745 return structType.getMembers();
746 if (
auto structType = dyn_cast<UnpackedStructType>(type))
747 return structType.getMembers();
748 assert(0 &&
"expected StructType or UnpackedStructType");
758LogicalResult StructCreateOp::verify() {
762 if (getFields().size() != members.size())
763 return emitOpError() <<
"has " << getFields().size()
764 <<
" operands, but result type requires "
768 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
769 auto [value, member] = pair;
770 if (value.getType() != member.type)
771 return emitOpError() <<
"operand #" << index <<
" has type "
772 << value.getType() <<
", but struct field "
773 << member.name <<
" requires " << member.type;
778OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
779 SmallVector<NamedAttribute> fields;
780 for (
auto [member, field] :
784 fields.push_back(NamedAttribute(member.name, field));
786 return DictionaryAttr::get(getContext(), fields);
793LogicalResult StructExtractOp::verify() {
796 return emitOpError() <<
"extracts field " << getFieldNameAttr()
797 <<
" which does not exist in " << getInput().getType();
798 if (type != getType())
799 return emitOpError() <<
"result type " << getType()
800 <<
" must match struct field type " << type;
804OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
806 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
807 if (
auto value = fields.get(getFieldNameAttr()))
811 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
812 if (inject.getFieldNameAttr() == getFieldNameAttr())
813 return inject.getNewValue();
818 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
820 return create.getFields()[*index];
831LogicalResult StructExtractRefOp::verify() {
833 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
835 return emitOpError() <<
"extracts field " << getFieldNameAttr()
836 <<
" which does not exist in " << getInput().getType();
837 if (type != getType().getNestedType())
838 return emitOpError() <<
"result ref of type " << getType().getNestedType()
839 <<
" must match struct field type " << type;
843bool StructExtractRefOp::canRewire(
844 const DestructurableMemorySlot &slot,
845 SmallPtrSetImpl<Attribute> &usedIndices,
846 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
847 const DataLayout &dataLayout) {
848 if (slot.ptr != getInput())
850 auto index = getFieldNameAttr();
851 if (!index || !slot.subelementTypes.contains(index))
853 usedIndices.insert(index);
858StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
859 DenseMap<Attribute, MemorySlot> &subslots,
860 OpBuilder &builder,
const DataLayout &dataLayout) {
861 auto index = getFieldNameAttr();
862 const MemorySlot &memorySlot = subslots.at(index);
863 replaceAllUsesWith(memorySlot.ptr);
864 getInputMutable().drop();
866 return DeletionKind::Keep;
873LogicalResult StructInjectOp::verify() {
876 return emitOpError() <<
"injects field " << getFieldNameAttr()
877 <<
" which does not exist in " << getInput().getType();
878 if (type != getNewValue().getType())
879 return emitOpError() <<
"injected value " << getNewValue().getType()
880 <<
" must match struct field type " << type;
884OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
885 auto input = adaptor.getInput();
886 auto newValue = adaptor.getNewValue();
887 if (!input || !newValue)
889 NamedAttrList fields(cast<DictionaryAttr>(input));
890 fields.set(getFieldNameAttr(), newValue);
891 return fields.getDictionary(getContext());
894LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
895 PatternRewriter &rewriter) {
900 SmallPtrSet<Operation *, 4> injectOps;
901 DenseMap<StringAttr, Value> fieldValues;
903 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
904 if (!injectOps.insert(injectOp).second)
906 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
907 input = injectOp.getInput();
909 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
910 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
911 fieldValues.insert({member.name, value});
914 if (fieldValues.size() == members.size()) {
915 SmallVector<Value> values;
916 values.reserve(fieldValues.size());
917 for (
auto member : members)
918 values.push_back(fieldValues.lookup(member.name));
919 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
925 if (injectOps.size() == fieldValues.size())
930 for (
auto member : members)
931 if (auto value = fieldValues.lookup(member.name))
932 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
934 rewriter.replaceOp(op, input);
942LogicalResult UnionCreateOp::verify() {
945 return TypeSwitch<Type, LogicalResult>(getType())
946 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
947 auto members = type.getMembers();
948 auto resultType = getType();
950 for (
const auto &member : members)
951 if (member.name == fieldName && member.type == resultType)
953 emitOpError(
"input type must match the union field type");
956 .Default([
this](
auto &) {
957 emitOpError(
"input type must be UnionType or UnpackedUnionType");
966LogicalResult UnionExtractOp::verify() {
969 return TypeSwitch<Type, LogicalResult>(getInput().getType())
970 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
971 auto members = type.getMembers();
973 auto resultType = getType();
974 for (
const auto &member : members)
975 if (member.name == fieldName && member.type == resultType)
977 emitOpError(
"result type must match the union field type");
980 .Default([
this](
auto &) {
981 emitOpError(
"input type must be UnionType or UnpackedUnionType");
990LogicalResult UnionExtractRefOp::verify() {
993 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
994 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
995 auto members = type.getMembers();
997 auto resultType = getType().getNestedType();
998 for (
const auto &member : members)
999 if (member.name == fieldName && member.type == resultType)
1001 emitOpError(
"result type must match the union field type");
1004 .Default([
this](
auto &) {
1005 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1014LogicalResult YieldOp::verify() {
1016 auto cond = dyn_cast<ConditionalOp>(*(*this).getParentOp());
1018 emitOpError(
"must have a conditional parent");
1023 auto condType = cond.getType();
1024 auto yieldType = getOperand().getType();
1025 if (condType != yieldType) {
1026 emitOpError(
"yield type must match conditional. Expected ")
1027 << condType <<
", but got " << yieldType <<
".";
1038OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1040 if (getInput().getType() == getResult().getType())
1044 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1045 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1046 auto toIntType = dyn_cast<IntType>(getResult().getType());
1047 if (intInput && fromIntType && toIntType &&
1048 fromIntType.getWidth() == toIntType.getWidth()) {
1051 if (toIntType.getDomain() == Domain::FourValued)
1056 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1066OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1068 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1069 return reverseOp.getInput();
1073 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1074 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1083OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1088 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1098OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1100 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1101 return reverseOp.getInput();
1104 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1105 return FVIntegerAttr::get(getContext(), attr.getValue());
1114OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1116 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1117 return reverseOp.getInput();
1120 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1121 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1131OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1133 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1134 auto width = getType().getWidth();
1135 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1145OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1147 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1148 auto width = getType().getWidth();
1149 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1159OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1161 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1162 auto width = getType().getWidth();
1163 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1173OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1175 if (getInput().getType() == getResult().getType())
1184bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1186bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1187 return getDst() == slot.ptr;
1190Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1192 const DataLayout &dataLayout) {
1196bool BlockingAssignOp::canUsesBeRemoved(
1197 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1198 SmallVectorImpl<OpOperand *> &newBlockingUses,
1199 const DataLayout &dataLayout) {
1201 if (blockingUses.size() != 1)
1203 Value blockingUse = (*blockingUses.begin())->
get();
1204 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1205 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1208DeletionKind BlockingAssignOp::removeBlockingUses(
1209 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1210 OpBuilder &builder, Value reachingDefinition,
1211 const DataLayout &dataLayout) {
1212 return DeletionKind::Delete;
1219bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1220 return getInput() == slot.ptr;
1223bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1225Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1226 Value reachingDef,
const DataLayout &dataLayout) {
1227 llvm_unreachable(
"getStored should not be called on ReadOp");
1230bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1231 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1232 SmallVectorImpl<OpOperand *> &newBlockingUses,
1233 const DataLayout &dataLayout) {
1235 if (blockingUses.size() != 1)
1237 Value blockingUse = (*blockingUses.begin())->
get();
1238 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1239 getResult().getType() == slot.elemType;
1243ReadOp::removeBlockingUses(
const MemorySlot &slot,
1244 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1245 OpBuilder &builder, Value reachingDefinition,
1246 const DataLayout &dataLayout) {
1247 getResult().replaceAllUsesWith(reachingDefinition);
1248 return DeletionKind::Delete;
1257 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1258 if (lhsValue && lhsValue.getValue() == 1)
1261 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1262 if (rhsValue && rhsValue.getValue().isZero())
1263 return FVIntegerAttr::get(ctxt,
1264 FVInt(rhsValue.getValue().getBitWidth(), 1));
1269OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1273LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1274 Location loc = op.getLoc();
1275 auto intType = cast<IntType>(op.getRhs().getType());
1276 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1277 if (baseOp.getValue() == 2) {
1278 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1279 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1280 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1281 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1282 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1283 op, op.getLhs().getType(), isNegative);
1284 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1285 rewriter.setInsertionPointToStart(thenBlock);
1286 YieldOp::create(rewriter, loc, constZero);
1287 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1288 rewriter.setInsertionPointToStart(elseBlock);
1289 YieldOp::create(rewriter, loc, shift);
1301OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1305LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1306 Location loc = op.getLoc();
1307 auto intType = cast<IntType>(op.getRhs().getType());
1308 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1309 if (baseOp.getValue() == 2) {
1310 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1311 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1323OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1324 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1325 if (intAttr.getValue().isZero())
1335OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1336 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1337 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1339 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1347OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1348 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1349 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1351 return FVIntegerAttr::get(getContext(),
1352 lhs.getValue().udiv(rhs.getValue()));
1360OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1361 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1362 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1364 return FVIntegerAttr::get(getContext(),
1365 lhs.getValue().sdiv(rhs.getValue()));
1374#define GET_OP_CLASSES
1375#include "circt/Dialect/Moore/Moore.cpp.inc"
1376#include "circt/Dialect/Moore/MooreEnums.cpp.inc"
assert(baseType &&"element must be base type")
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.
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