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 ConstantRealOp::inferReturnTypes(
650 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
651 DictionaryAttr attrs, mlir::OpaqueProperties properties,
652 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
653 ConstantRealOp::Adaptor adaptor(operands, attrs, properties);
654 results.push_back(RealType::get(
656 adaptor.getValueAttr().getType().getIntOrFloatBitWidth())));
664LogicalResult ConcatOp::inferReturnTypes(
665 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
666 DictionaryAttr attrs, mlir::OpaqueProperties properties,
667 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
668 Domain domain = Domain::TwoValued;
670 for (
auto operand : operands) {
671 auto type = cast<IntType>(operand.getType());
672 if (type.getDomain() == Domain::FourValued)
673 domain = Domain::FourValued;
674 width += type.getWidth();
676 results.push_back(IntType::get(context, width, domain));
684LogicalResult ConcatRefOp::inferReturnTypes(
685 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
686 DictionaryAttr attrs, mlir::OpaqueProperties properties,
687 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
688 Domain domain = Domain::TwoValued;
690 for (Value operand : operands) {
691 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
692 PackedType packedType = dyn_cast<PackedType>(nestedType);
698 if (packedType.
getDomain() == Domain::FourValued)
699 domain = Domain::FourValued;
702 std::optional<int> bitSize = packedType.
getBitSize();
708 results.push_back(RefType::get(IntType::get(context, width, domain)));
717 if (
auto arrayType = dyn_cast<ArrayType>(type))
718 return {arrayType.getSize(), arrayType.getElementType()};
719 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
720 return {arrayType.getSize(), arrayType.getElementType()};
721 assert(0 &&
"expected ArrayType or UnpackedArrayType");
725LogicalResult ArrayCreateOp::verify() {
729 if (getElements().size() != size)
730 return emitOpError() <<
"has " << getElements().size()
731 <<
" operands, but result type requires " << size;
737 auto value = getElements()[0];
739 return emitOpError() <<
"operands have type " << value.getType()
750 if (
auto structType = dyn_cast<StructType>(type))
751 return structType.getFieldIndex(name);
752 if (
auto structType = dyn_cast<UnpackedStructType>(type))
753 return structType.getFieldIndex(name);
754 assert(0 &&
"expected StructType or UnpackedStructType");
759 if (
auto structType = dyn_cast<StructType>(type))
760 return structType.getMembers();
761 if (
auto structType = dyn_cast<UnpackedStructType>(type))
762 return structType.getMembers();
763 assert(0 &&
"expected StructType or UnpackedStructType");
773LogicalResult StructCreateOp::verify() {
777 if (getFields().size() != members.size())
778 return emitOpError() <<
"has " << getFields().size()
779 <<
" operands, but result type requires "
783 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
784 auto [value, member] = pair;
785 if (value.getType() != member.type)
786 return emitOpError() <<
"operand #" << index <<
" has type "
787 << value.getType() <<
", but struct field "
788 << member.name <<
" requires " << member.type;
793OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
794 SmallVector<NamedAttribute> fields;
795 for (
auto [member, field] :
799 fields.push_back(NamedAttribute(member.name, field));
801 return DictionaryAttr::get(getContext(), fields);
808LogicalResult StructExtractOp::verify() {
811 return emitOpError() <<
"extracts field " << getFieldNameAttr()
812 <<
" which does not exist in " << getInput().getType();
813 if (type != getType())
814 return emitOpError() <<
"result type " << getType()
815 <<
" must match struct field type " << type;
819OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
821 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
822 if (
auto value = fields.get(getFieldNameAttr()))
826 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
827 if (inject.getFieldNameAttr() == getFieldNameAttr())
828 return inject.getNewValue();
833 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
835 return create.getFields()[*index];
846LogicalResult StructExtractRefOp::verify() {
848 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
850 return emitOpError() <<
"extracts field " << getFieldNameAttr()
851 <<
" which does not exist in " << getInput().getType();
852 if (type != getType().getNestedType())
853 return emitOpError() <<
"result ref of type " << getType().getNestedType()
854 <<
" must match struct field type " << type;
858bool StructExtractRefOp::canRewire(
859 const DestructurableMemorySlot &slot,
860 SmallPtrSetImpl<Attribute> &usedIndices,
861 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
862 const DataLayout &dataLayout) {
863 if (slot.ptr != getInput())
865 auto index = getFieldNameAttr();
866 if (!index || !slot.subelementTypes.contains(index))
868 usedIndices.insert(index);
873StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
874 DenseMap<Attribute, MemorySlot> &subslots,
875 OpBuilder &builder,
const DataLayout &dataLayout) {
876 auto index = getFieldNameAttr();
877 const MemorySlot &memorySlot = subslots.at(index);
878 replaceAllUsesWith(memorySlot.ptr);
879 getInputMutable().drop();
881 return DeletionKind::Keep;
888LogicalResult StructInjectOp::verify() {
891 return emitOpError() <<
"injects field " << getFieldNameAttr()
892 <<
" which does not exist in " << getInput().getType();
893 if (type != getNewValue().getType())
894 return emitOpError() <<
"injected value " << getNewValue().getType()
895 <<
" must match struct field type " << type;
899OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
900 auto input = adaptor.getInput();
901 auto newValue = adaptor.getNewValue();
902 if (!input || !newValue)
904 NamedAttrList fields(cast<DictionaryAttr>(input));
905 fields.set(getFieldNameAttr(), newValue);
906 return fields.getDictionary(getContext());
909LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
910 PatternRewriter &rewriter) {
915 SmallPtrSet<Operation *, 4> injectOps;
916 DenseMap<StringAttr, Value> fieldValues;
918 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
919 if (!injectOps.insert(injectOp).second)
921 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
922 input = injectOp.getInput();
924 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
925 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
926 fieldValues.insert({member.name, value});
929 if (fieldValues.size() == members.size()) {
930 SmallVector<Value> values;
931 values.reserve(fieldValues.size());
932 for (
auto member : members)
933 values.push_back(fieldValues.lookup(member.name));
934 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
940 if (injectOps.size() == fieldValues.size())
945 for (
auto member : members)
946 if (auto value = fieldValues.lookup(member.name))
947 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
949 rewriter.replaceOp(op, input);
957LogicalResult UnionCreateOp::verify() {
960 return TypeSwitch<Type, LogicalResult>(getType())
961 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
962 auto members = type.getMembers();
963 auto resultType = getType();
965 for (
const auto &member : members)
966 if (member.name == fieldName && member.type == resultType)
968 emitOpError(
"input type must match the union field type");
971 .Default([
this](
auto &) {
972 emitOpError(
"input type must be UnionType or UnpackedUnionType");
981LogicalResult UnionExtractOp::verify() {
984 return TypeSwitch<Type, LogicalResult>(getInput().getType())
985 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
986 auto members = type.getMembers();
988 auto resultType = getType();
989 for (
const auto &member : members)
990 if (member.name == fieldName && member.type == resultType)
992 emitOpError(
"result type must match the union field type");
995 .Default([
this](
auto &) {
996 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1005LogicalResult UnionExtractRefOp::verify() {
1008 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1009 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1010 auto members = type.getMembers();
1012 auto resultType = getType().getNestedType();
1013 for (
const auto &member : members)
1014 if (member.name == fieldName && member.type == resultType)
1016 emitOpError(
"result type must match the union field type");
1019 .Default([
this](
auto &) {
1020 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1029LogicalResult YieldOp::verify() {
1031 auto cond = dyn_cast<ConditionalOp>(*(*this).getParentOp());
1033 emitOpError(
"must have a conditional parent");
1038 auto condType = cond.getType();
1039 auto yieldType = getOperand().getType();
1040 if (condType != yieldType) {
1041 emitOpError(
"yield type must match conditional. Expected ")
1042 << condType <<
", but got " << yieldType <<
".";
1053OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1055 if (getInput().getType() == getResult().getType())
1059 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1060 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1061 auto toIntType = dyn_cast<IntType>(getResult().getType());
1062 if (intInput && fromIntType && toIntType &&
1063 fromIntType.getWidth() == toIntType.getWidth()) {
1066 if (toIntType.getDomain() == Domain::FourValued)
1071 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1081OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1083 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1084 return reverseOp.getInput();
1088 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1089 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1098OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1103 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1113OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1115 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1116 return reverseOp.getInput();
1119 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1120 return FVIntegerAttr::get(getContext(), attr.getValue());
1129OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1131 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1132 return reverseOp.getInput();
1135 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1136 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1146OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1148 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1149 auto width = getType().getWidth();
1150 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1160OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1162 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1163 auto width = getType().getWidth();
1164 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1174OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1176 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1177 auto width = getType().getWidth();
1178 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1188OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1190 if (getInput().getType() == getResult().getType())
1199bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1201bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1202 return getDst() == slot.ptr;
1205Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1207 const DataLayout &dataLayout) {
1211bool BlockingAssignOp::canUsesBeRemoved(
1212 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1213 SmallVectorImpl<OpOperand *> &newBlockingUses,
1214 const DataLayout &dataLayout) {
1216 if (blockingUses.size() != 1)
1218 Value blockingUse = (*blockingUses.begin())->
get();
1219 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1220 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1223DeletionKind BlockingAssignOp::removeBlockingUses(
1224 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1225 OpBuilder &builder, Value reachingDefinition,
1226 const DataLayout &dataLayout) {
1227 return DeletionKind::Delete;
1234bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1235 return getInput() == slot.ptr;
1238bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1240Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1241 Value reachingDef,
const DataLayout &dataLayout) {
1242 llvm_unreachable(
"getStored should not be called on ReadOp");
1245bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1246 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1247 SmallVectorImpl<OpOperand *> &newBlockingUses,
1248 const DataLayout &dataLayout) {
1250 if (blockingUses.size() != 1)
1252 Value blockingUse = (*blockingUses.begin())->
get();
1253 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1254 getResult().getType() == slot.elemType;
1258ReadOp::removeBlockingUses(
const MemorySlot &slot,
1259 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1260 OpBuilder &builder, Value reachingDefinition,
1261 const DataLayout &dataLayout) {
1262 getResult().replaceAllUsesWith(reachingDefinition);
1263 return DeletionKind::Delete;
1272 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1273 if (lhsValue && lhsValue.getValue() == 1)
1276 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1277 if (rhsValue && rhsValue.getValue().isZero())
1278 return FVIntegerAttr::get(ctxt,
1279 FVInt(rhsValue.getValue().getBitWidth(), 1));
1284OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1288LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1289 Location loc = op.getLoc();
1290 auto intType = cast<IntType>(op.getRhs().getType());
1291 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1292 if (baseOp.getValue() == 2) {
1293 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1294 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1295 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1296 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1297 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1298 op, op.getLhs().getType(), isNegative);
1299 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1300 rewriter.setInsertionPointToStart(thenBlock);
1301 YieldOp::create(rewriter, loc, constZero);
1302 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1303 rewriter.setInsertionPointToStart(elseBlock);
1304 YieldOp::create(rewriter, loc, shift);
1316OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1320LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1321 Location loc = op.getLoc();
1322 auto intType = cast<IntType>(op.getRhs().getType());
1323 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1324 if (baseOp.getValue() == 2) {
1325 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1326 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1338OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1339 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1340 if (intAttr.getValue().isZero())
1350OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1351 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1352 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1354 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1362OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1363 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1364 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1366 return FVIntegerAttr::get(getContext(),
1367 lhs.getValue().udiv(rhs.getValue()));
1375OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1376 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1377 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1379 return FVIntegerAttr::get(getContext(),
1380 lhs.getValue().sdiv(rhs.getValue()));
1388LogicalResult ClassDeclOp::verify() {
1389 mlir::Region &body = getBody();
1391 return mlir::success();
1393 auto &block = body.front();
1394 for (mlir::Operation &op : block) {
1397 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1398 circt::moore::ClassMethodDeclOp>(&op))
1401 return emitOpError()
1402 <<
"body may only contain 'moore.class.propertydecl' operations";
1404 return mlir::success();
1407LogicalResult ClassNewOp::verify() {
1410 auto handleTy = cast<ClassHandleType>(getResult().getType());
1411 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1413 return emitOpError(
"result type is missing a class symbol");
1416 mlir::Operation *sym =
1417 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1419 return emitOpError(
"referenced class symbol `")
1420 << classSym <<
"` was not found";
1422 if (!llvm::isa<ClassDeclOp>(sym))
1423 return emitOpError(
"symbol `")
1424 << classSym <<
"` does not name a `moore.class.classdecl`";
1426 return mlir::success();
1429void ClassNewOp::getEffects(
1430 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1433 effects.emplace_back(MemoryEffects::Allocate::get());
1437ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1439 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1441 return emitOpError() <<
"operand must be !moore.class<...>; got "
1442 << getOperand().getType();
1444 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1446 return emitOpError() <<
"result must be !moore.class<...>; got "
1447 << getResult().getType();
1452 auto *op = getOperation();
1455 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1457 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1458 if (!srcDeclOp || !dstDeclOp)
1459 return emitOpError() <<
"failed to resolve class symbol(s): src="
1460 << srcTy.getClassSym()
1461 <<
", dst=" << dstTy.getClassSym();
1463 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1464 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1465 if (!srcDecl || !dstDecl)
1466 return emitOpError()
1467 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1468 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1475 auto baseSym = cur.getBaseAttr();
1479 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1480 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1483 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1484 << dstTy.getClassSym()
1485 <<
" (destination is not a base class)";
1488ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1490 Type instTy = getInstance().getType();
1491 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1493 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1497 SymbolRefAttr classSym = handleTy.getClassSym();
1499 return emitOpError(
"instance type is missing a class symbol");
1503 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1505 return emitOpError(
"referenced class symbol `")
1506 << classSym <<
"` was not found";
1507 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1509 return emitOpError(
"symbol `")
1510 << classSym <<
"` does not name a `moore.class.classdecl`";
1513 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1515 return emitOpError(
"missing field symbol");
1517 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1519 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1521 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1523 return emitOpError(
"symbol `")
1524 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1527 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1529 return emitOpError(
"result must be a !moore.ref<T>");
1531 Type expectedElemTy = fieldDecl.getPropertyType();
1532 if (resRefTy.getNestedType() != expectedElemTy)
1533 return emitOpError(
"result element type (")
1534 << resRefTy.getNestedType() <<
") does not match field type ("
1535 << expectedElemTy <<
")";
1545#define GET_OP_CLASSES
1546#include "circt/Dialect/Moore/Moore.cpp.inc"
1547#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.
RealWidth
The type of floating point / real number behind a RealType.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ParseResult parseInputPortList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inputs, SmallVectorImpl< Type > &inputTypes, ArrayAttr &inputNames)
Parse a list of instance input ports.
void printOutputPortList(OpAsmPrinter &p, Operation *op, TypeRange resultTypes, ArrayAttr resultNames)
Print a list of instance output ports.
void printFVInt(AsmPrinter &p, const FVInt &value)
Print a four-valued integer usign an AsmPrinter.
ParseResult parseFVInt(AsmParser &p, FVInt &result)
Parse a four-valued integer using an AsmParser.
void printInputPortList(OpAsmPrinter &p, Operation *op, OperandRange inputs, TypeRange inputTypes, ArrayAttr inputNames)
Print a list of instance input ports.
ParseResult parseOutputPortList(OpAsmParser &parser, SmallVectorImpl< Type > &resultTypes, ArrayAttr &resultNames)
Parse a list of instance output ports.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn