18#include "mlir/IR/Builders.h"
19#include "llvm/ADT/APSInt.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include <mlir/Dialect/Func/IR/FuncOps.h>
32void SVModuleOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
33 llvm::StringRef name, hw::ModuleType type) {
34 state.addAttribute(SymbolTable::getSymbolAttrName(),
35 builder.getStringAttr(name));
36 state.addAttribute(getModuleTypeAttrName(state.name), TypeAttr::get(type));
40void SVModuleOp::print(OpAsmPrinter &p) {
44 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
45 if (
auto visibility = (*this)->getAttrOfType<StringAttr>(visibilityAttrName))
46 p << visibility.getValue() <<
' ';
48 p.printSymbolName(SymbolTable::getSymbolName(*this).getValue());
52 p.printRegion(getBodyRegion(),
false,
55 p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs(),
59ParseResult SVModuleOp::parse(OpAsmParser &parser, OperationState &result) {
61 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
65 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
70 SmallVector<hw::module_like_impl::PortParse> ports;
75 result.addAttribute(getModuleTypeAttrName(result.name), modType);
78 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
82 SmallVector<OpAsmParser::Argument, 4> entryArgs;
83 for (
auto &port : ports)
85 entryArgs.push_back(port);
88 auto &bodyRegion = *result.addRegion();
89 if (parser.parseRegion(bodyRegion, entryArgs))
92 ensureTerminator(bodyRegion, parser.getBuilder(), result.location);
96void SVModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
98 if (®ion != &getBodyRegion())
101 for (
auto [index, arg] :
llvm::enumerate(region.front().getArguments()))
102 setNameFn(arg, moduleType.getInputNameAttr(index));
105OutputOp SVModuleOp::getOutputOp() {
106 return cast<OutputOp>(getBody()->getTerminator());
109OperandRange SVModuleOp::getOutputs() {
return getOutputOp().getOperands(); }
115LogicalResult OutputOp::verify() {
116 auto module = getParentOp();
119 auto outputTypes =
module.getModuleType().getOutputTypes();
120 if (outputTypes.size() != getNumOperands())
121 return emitOpError(
"has ")
122 << getNumOperands() <<
" operands, but enclosing module @"
123 <<
module.getSymName() << " has " << outputTypes.size()
127 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
128 if (outputTypes[i] != getOperand(i).getType())
129 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
130 <<
") does not match output type (" << outputTypes[i]
131 <<
") of module @" <<
module.getSymName();
140LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
143 symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
145 return emitOpError(
"references unknown symbol @") << getModuleName();
148 auto module = dyn_cast<SVModuleOp>(symbol);
150 return emitOpError(
"must reference a 'moore.module', but @")
151 << getModuleName() <<
" is a '" << symbol->getName() <<
"'";
154 auto moduleType =
module.getModuleType();
155 auto inputTypes = moduleType.getInputTypes();
157 if (inputTypes.size() != getNumOperands())
158 return emitOpError(
"has ")
159 << getNumOperands() <<
" operands, but target module @"
160 <<
module.getSymName() << " has " << inputTypes.size() << " inputs";
162 for (
unsigned i = 0, e = inputTypes.size(); i != e; ++i)
163 if (inputTypes[i] != getOperand(i).getType())
164 return emitOpError() <<
"operand " << i <<
" (" << getOperand(i).getType()
165 <<
") does not match input type (" << inputTypes[i]
166 <<
") of module @" <<
module.getSymName();
169 auto outputTypes = moduleType.getOutputTypes();
171 if (outputTypes.size() != getNumResults())
172 return emitOpError(
"has ")
173 << getNumOperands() <<
" results, but target module @"
174 <<
module.getSymName() << " has " << outputTypes.size()
177 for (
unsigned i = 0, e = outputTypes.size(); i != e; ++i)
178 if (outputTypes[i] != getResult(i).getType())
179 return emitOpError() <<
"result " << i <<
" (" << getResult(i).getType()
180 <<
") does not match output type (" << outputTypes[i]
181 <<
") of module @" <<
module.getSymName();
186void InstanceOp::print(OpAsmPrinter &p) {
188 p.printAttributeWithoutType(getInstanceNameAttr());
190 p.printAttributeWithoutType(getModuleNameAttr());
196 p.printOptionalAttrDict(getOperation()->getAttrs(), getAttributeNames());
199ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
201 StringAttr instanceName;
202 if (parser.parseAttribute(instanceName,
"instanceName", result.attributes))
206 FlatSymbolRefAttr moduleName;
207 if (parser.parseAttribute(moduleName,
"moduleName", result.attributes))
211 auto loc = parser.getCurrentLocation();
212 SmallVector<OpAsmParser::UnresolvedOperand> inputs;
213 SmallVector<Type> types;
217 if (parser.resolveOperands(inputs, types, loc, result.operands))
219 result.addAttribute(
"inputNames", names);
222 if (parser.parseArrow())
229 result.addAttribute(
"outputNames", names);
230 result.addTypes(types);
233 if (parser.parseOptionalAttrDict(result.attributes))
240 SmallString<32> name;
243 auto baseLen = name.size();
245 for (
auto [result, portName] :
246 llvm::zip(getOutputs(), getOutputNames().getAsRange<StringAttr>())) {
247 if (!portName || portName.empty())
249 name.resize(baseLen);
250 name += portName.getValue();
251 setNameFn(result, name);
261 setNameFn(getResult(), *
getName());
264LogicalResult VariableOp::canonicalize(VariableOp op,
265 PatternRewriter &rewriter) {
269 auto initial = op.getInitial();
270 if (initial && mlir::mayHaveSSADominance(*op->getParentRegion())) {
271 rewriter.modifyOpInPlace(op, [&] { op.getInitialMutable().clear(); });
272 rewriter.setInsertionPointAfter(op);
273 BlockingAssignOp::create(rewriter, initial.getLoc(), op, initial);
280 auto *block = op->getBlock();
281 ContinuousAssignOp uniqueAssignOp;
282 for (
auto *user : op->getUsers()) {
284 if (user->getBlock() != block)
288 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
291 uniqueAssignOp = assignOp;
296 if (!isa<ReadOp>(user))
304 Value assignedValue = uniqueAssignOp.getSrc();
305 if (
auto name = op.getNameAttr(); name && !name.empty())
306 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
307 uniqueAssignOp.getSrc());
310 rewriter.eraseOp(uniqueAssignOp);
311 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
312 auto readOp = cast<ReadOp>(user);
313 rewriter.replaceOp(readOp, assignedValue);
317 rewriter.eraseOp(op);
321SmallVector<MemorySlot> VariableOp::getPromotableSlots() {
324 if (mlir::mayBeGraphRegion(*getOperation()->getParentRegion()) ||
330 if (!isa<PackedType>(getType().getNestedType()))
333 return {MemorySlot{getResult(), getType().getNestedType()}};
336Value VariableOp::getDefaultValue(
const MemorySlot &slot, OpBuilder &builder) {
337 auto packedType = dyn_cast<PackedType>(slot.elemType);
340 auto bitWidth = packedType.getBitSize();
343 auto fvint = packedType.getDomain() == Domain::FourValued
345 :
FVInt::getZero(*bitWidth);
346 Value value = ConstantOp::create(
348 IntType::get(getContext(), *bitWidth, packedType.getDomain()), fvint);
349 if (value.getType() != packedType)
350 ConversionOp::create(builder,
getLoc(), packedType, value);
354void VariableOp::handleBlockArgument(
const MemorySlot &slot,
355 BlockArgument argument,
356 OpBuilder &builder) {}
358std::optional<mlir::PromotableAllocationOpInterface>
359VariableOp::handlePromotionComplete(
const MemorySlot &slot, Value defaultValue,
360 OpBuilder &builder) {
361 if (defaultValue && defaultValue.use_empty())
362 defaultValue.getDefiningOp()->erase();
367SmallVector<DestructurableMemorySlot> VariableOp::getDestructurableSlots() {
368 if (isa<SVModuleOp>(getOperation()->getParentOp()))
373 auto refType = getType();
374 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(refType);
378 auto destructuredType = destructurable.getSubelementIndexMap();
379 if (!destructuredType)
382 return {DestructurableMemorySlot{{getResult(), refType}, *destructuredType}};
385DenseMap<Attribute, MemorySlot> VariableOp::destructure(
386 const DestructurableMemorySlot &slot,
387 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
388 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
389 assert(slot.ptr == getResult());
391 builder.setInsertionPointAfter(*
this);
393 auto destructurableType = cast<DestructurableTypeInterface>(getType());
394 DenseMap<Attribute, MemorySlot> slotMap;
395 for (Attribute index : usedIndices) {
396 auto elemType = cast<RefType>(destructurableType.getTypeAtIndex(index));
397 assert(elemType &&
"used index must exist");
399 if (
auto name =
getName(); name && !name->empty())
400 varName = StringAttr::get(
401 getContext(), (*name) +
"." + cast<StringAttr>(index).getValue());
403 VariableOp::create(builder,
getLoc(), elemType, varName, Value());
404 newAllocators.push_back(varOp);
405 slotMap.try_emplace<MemorySlot>(index, {varOp.getResult(), elemType});
411std::optional<DestructurableAllocationOpInterface>
412VariableOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
413 OpBuilder &builder) {
414 assert(slot.ptr == getResult());
425 setNameFn(getResult(), *
getName());
428LogicalResult NetOp::canonicalize(NetOp op, PatternRewriter &rewriter) {
429 bool modified =
false;
433 auto *block = op->getBlock();
434 ContinuousAssignOp uniqueAssignOp;
435 bool allUsesAreReads =
true;
436 for (
auto *user : op->getUsers()) {
438 if (user->getBlock() != block)
442 if (
auto assignOp = dyn_cast<ContinuousAssignOp>(user)) {
445 uniqueAssignOp = assignOp;
450 if (!isa<ReadOp>(user))
451 allUsesAreReads =
false;
456 if (uniqueAssignOp && !op.getAssignment()) {
457 rewriter.modifyOpInPlace(
458 op, [&] { op.getAssignmentMutable().assign(uniqueAssignOp.getSrc()); });
459 rewriter.eraseOp(uniqueAssignOp);
467 if (!uniqueAssignOp && allUsesAreReads && op.getAssignment()) {
470 auto assignedValue = op.getAssignment();
471 if (
auto name = op.getNameAttr(); name && !name.empty())
472 assignedValue = AssignedVariableOp::create(rewriter, op.getLoc(), name,
477 for (
auto *user :
llvm::make_early_inc_range(op->getUsers())) {
478 auto readOp = cast<ReadOp>(user);
479 rewriter.replaceOp(readOp, assignedValue);
481 rewriter.eraseOp(op);
485 return success(modified);
494 setNameFn(getResult(), *
getName());
497LogicalResult AssignedVariableOp::canonicalize(AssignedVariableOp op,
498 PatternRewriter &rewriter) {
501 if (
auto otherOp = op.getInput().getDefiningOp<AssignedVariableOp>()) {
502 if (otherOp.getNameAttr() == op.getNameAttr()) {
503 rewriter.replaceOp(op, otherOp);
509 if (
auto blockArg = dyn_cast<BlockArgument>(op.getInput())) {
511 dyn_cast<SVModuleOp>(blockArg.getOwner()->getParentOp())) {
512 auto moduleType = moduleOp.getModuleType();
513 auto portName = moduleType.getInputNameAttr(blockArg.getArgNumber());
514 if (portName == op.getNameAttr()) {
515 rewriter.replaceOp(op, blockArg);
522 for (
auto &use : op->getUses()) {
523 auto *useOwner = use.getOwner();
524 if (
auto outputOp = dyn_cast<OutputOp>(useOwner)) {
525 if (
auto moduleOp = dyn_cast<SVModuleOp>(outputOp->getParentOp())) {
526 auto moduleType = moduleOp.getModuleType();
527 auto portName = moduleType.getOutputNameAttr(use.getOperandNumber());
528 if (portName == op.getNameAttr()) {
529 rewriter.replaceOp(op, op.getInput());
544LogicalResult GlobalVariableOp::verifyRegions() {
545 if (
auto *block = getInitBlock()) {
546 auto &terminator = block->back();
547 if (!isa<YieldOp>(terminator))
548 return emitOpError() <<
"must have a 'moore.yield' terminator";
553Block *GlobalVariableOp::getInitBlock() {
554 if (getInitRegion().
empty())
556 return &getInitRegion().front();
564GetGlobalVariableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
567 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
569 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
572 auto var = dyn_cast<GlobalVariableOp>(symbol);
574 return emitOpError() <<
"must reference a 'moore.global_variable', but "
575 << getGlobalNameAttr() <<
" is a '"
576 << symbol->getName() <<
"'";
579 auto expType = var.getType();
580 auto actType = getType().getNestedType();
581 if (expType != actType)
582 return emitOpError() <<
"returns a " << actType <<
" reference, but "
583 << getGlobalNameAttr() <<
" is of type " << expType;
592void ConstantOp::print(OpAsmPrinter &p) {
595 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
597 p.printStrippedAttrOrType(getType());
600ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
603 auto valueLoc = parser.getCurrentLocation();
608 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
613 if (parser.parseCustomTypeWithFallback(type))
621 value = value.
sext(type.getWidth());
622 }
else if (type.getWidth() < value.
getBitWidth()) {
625 unsigned neededBits =
627 if (type.getWidth() < neededBits)
628 return parser.emitError(valueLoc)
629 <<
"value requires " << neededBits
630 <<
" bits, but result type only has " << type.getWidth();
631 value = value.
trunc(type.getWidth());
636 if (value.
hasUnknown() && type.getDomain() != Domain::FourValued)
637 return parser.emitError(valueLoc)
638 <<
"value contains X or Z bits, but result type " << type
639 <<
" only allows two-valued bits";
642 auto attrValue = FVIntegerAttr::get(parser.getContext(), value);
643 result.addAttribute(
"value", attrValue);
644 result.addTypes(type);
648LogicalResult ConstantOp::verify() {
649 auto attrWidth = getValue().getBitWidth();
650 auto typeWidth = getType().getWidth();
651 if (attrWidth != typeWidth)
652 return emitError(
"attribute width ")
653 << attrWidth <<
" does not match return type's width " << typeWidth;
657void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
658 const FVInt &value) {
660 "FVInt width must match type width");
661 build(builder, result, type, FVIntegerAttr::get(builder.getContext(), value));
664void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
665 const APInt &value) {
666 assert(type.getWidth() == value.getBitWidth() &&
667 "APInt width must match type width");
668 build(builder, result, type,
FVInt(value));
675void ConstantOp::build(OpBuilder &builder, OperationState &result, IntType type,
676 int64_t value,
bool isSigned) {
677 build(builder, result, type,
678 APInt(type.getWidth(), (uint64_t)value, isSigned));
681OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
682 assert(adaptor.getOperands().empty() &&
"constant has no operands");
683 return getValueAttr();
690OpFoldResult ConstantTimeOp::fold(FoldAdaptor adaptor) {
691 return getValueAttr();
698LogicalResult ConstantRealOp::inferReturnTypes(
699 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
700 DictionaryAttr attrs, mlir::OpaqueProperties properties,
701 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
702 ConstantRealOp::Adaptor adaptor(operands, attrs, properties);
703 results.push_back(RealType::get(
705 adaptor.getValueAttr().getType().getIntOrFloatBitWidth())));
713LogicalResult ConcatOp::inferReturnTypes(
714 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
715 DictionaryAttr attrs, mlir::OpaqueProperties properties,
716 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
717 Domain domain = Domain::TwoValued;
719 for (
auto operand : operands) {
720 auto type = cast<IntType>(operand.getType());
721 if (type.getDomain() == Domain::FourValued)
722 domain = Domain::FourValued;
723 width += type.getWidth();
725 results.push_back(IntType::get(context, width, domain));
733LogicalResult ConcatRefOp::inferReturnTypes(
734 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
735 DictionaryAttr attrs, mlir::OpaqueProperties properties,
736 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
737 Domain domain = Domain::TwoValued;
739 for (Value operand : operands) {
740 UnpackedType nestedType = cast<RefType>(operand.getType()).getNestedType();
741 PackedType packedType = dyn_cast<PackedType>(nestedType);
747 if (packedType.
getDomain() == Domain::FourValued)
748 domain = Domain::FourValued;
751 std::optional<int> bitSize = packedType.
getBitSize();
757 results.push_back(RefType::get(IntType::get(context, width, domain)));
766 if (
auto arrayType = dyn_cast<ArrayType>(type))
767 return {arrayType.getSize(), arrayType.getElementType()};
768 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type))
769 return {arrayType.getSize(), arrayType.getElementType()};
770 assert(0 &&
"expected ArrayType or UnpackedArrayType");
774LogicalResult ArrayCreateOp::verify() {
778 if (getElements().size() != size)
779 return emitOpError() <<
"has " << getElements().size()
780 <<
" operands, but result type requires " << size;
786 auto value = getElements()[0];
788 return emitOpError() <<
"operands have type " << value.getType()
799 if (
auto structType = dyn_cast<StructType>(type))
800 return structType.getFieldIndex(name);
801 if (
auto structType = dyn_cast<UnpackedStructType>(type))
802 return structType.getFieldIndex(name);
803 assert(0 &&
"expected StructType or UnpackedStructType");
808 if (
auto structType = dyn_cast<StructType>(type))
809 return structType.getMembers();
810 if (
auto structType = dyn_cast<UnpackedStructType>(type))
811 return structType.getMembers();
812 assert(0 &&
"expected StructType or UnpackedStructType");
822LogicalResult StructCreateOp::verify() {
826 if (getFields().size() != members.size())
827 return emitOpError() <<
"has " << getFields().size()
828 <<
" operands, but result type requires "
832 for (
auto [index, pair] :
llvm::enumerate(
llvm::zip(getFields(), members))) {
833 auto [value, member] = pair;
834 if (value.getType() != member.type)
835 return emitOpError() <<
"operand #" << index <<
" has type "
836 << value.getType() <<
", but struct field "
837 << member.name <<
" requires " << member.type;
842OpFoldResult StructCreateOp::fold(FoldAdaptor adaptor) {
843 SmallVector<NamedAttribute> fields;
844 for (
auto [member, field] :
848 fields.push_back(NamedAttribute(member.name, field));
850 return DictionaryAttr::get(getContext(), fields);
857LogicalResult StructExtractOp::verify() {
860 return emitOpError() <<
"extracts field " << getFieldNameAttr()
861 <<
" which does not exist in " << getInput().getType();
862 if (type != getType())
863 return emitOpError() <<
"result type " << getType()
864 <<
" must match struct field type " << type;
868OpFoldResult StructExtractOp::fold(FoldAdaptor adaptor) {
870 if (
auto fields = dyn_cast_or_null<DictionaryAttr>(adaptor.getInput()))
871 if (
auto value = fields.get(getFieldNameAttr()))
875 if (
auto inject = getInput().getDefiningOp<StructInjectOp>()) {
876 if (inject.getFieldNameAttr() == getFieldNameAttr())
877 return inject.getNewValue();
882 if (
auto create = getInput().getDefiningOp<StructCreateOp>()) {
884 return create.getFields()[*index];
895LogicalResult StructExtractRefOp::verify() {
897 cast<RefType>(getInput().getType()).getNestedType(), getFieldNameAttr());
899 return emitOpError() <<
"extracts field " << getFieldNameAttr()
900 <<
" which does not exist in " << getInput().getType();
901 if (type != getType().getNestedType())
902 return emitOpError() <<
"result ref of type " << getType().getNestedType()
903 <<
" must match struct field type " << type;
907bool StructExtractRefOp::canRewire(
908 const DestructurableMemorySlot &slot,
909 SmallPtrSetImpl<Attribute> &usedIndices,
910 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
911 const DataLayout &dataLayout) {
912 if (slot.ptr != getInput())
914 auto index = getFieldNameAttr();
915 if (!index || !slot.subelementTypes.contains(index))
917 usedIndices.insert(index);
922StructExtractRefOp::rewire(
const DestructurableMemorySlot &slot,
923 DenseMap<Attribute, MemorySlot> &subslots,
924 OpBuilder &builder,
const DataLayout &dataLayout) {
925 auto index = getFieldNameAttr();
926 const MemorySlot &memorySlot = subslots.at(index);
927 replaceAllUsesWith(memorySlot.ptr);
928 getInputMutable().drop();
930 return DeletionKind::Keep;
937LogicalResult StructInjectOp::verify() {
940 return emitOpError() <<
"injects field " << getFieldNameAttr()
941 <<
" which does not exist in " << getInput().getType();
942 if (type != getNewValue().getType())
943 return emitOpError() <<
"injected value " << getNewValue().getType()
944 <<
" must match struct field type " << type;
948OpFoldResult StructInjectOp::fold(FoldAdaptor adaptor) {
949 auto input = adaptor.getInput();
950 auto newValue = adaptor.getNewValue();
951 if (!input || !newValue)
953 NamedAttrList fields(cast<DictionaryAttr>(input));
954 fields.set(getFieldNameAttr(), newValue);
955 return fields.getDictionary(getContext());
958LogicalResult StructInjectOp::canonicalize(StructInjectOp op,
959 PatternRewriter &rewriter) {
964 SmallPtrSet<Operation *, 4> injectOps;
965 DenseMap<StringAttr, Value> fieldValues;
967 while (
auto injectOp = input.getDefiningOp<StructInjectOp>()) {
968 if (!injectOps.insert(injectOp).second)
970 fieldValues.insert({injectOp.getFieldNameAttr(), injectOp.getNewValue()});
971 input = injectOp.getInput();
973 if (
auto createOp = input.getDefiningOp<StructCreateOp>())
974 for (
auto [value, member] :
llvm::zip(createOp.getFields(), members))
975 fieldValues.insert({member.name, value});
978 if (fieldValues.size() == members.size()) {
979 SmallVector<Value> values;
980 values.reserve(fieldValues.size());
981 for (
auto member : members)
982 values.push_back(fieldValues.lookup(member.name));
983 rewriter.replaceOpWithNewOp<StructCreateOp>(op, op.getType(), values);
989 if (injectOps.size() == fieldValues.size())
994 for (
auto member : members)
995 if (auto value = fieldValues.lookup(member.name))
996 input = StructInjectOp::create(rewriter, op.
getLoc(), op.getType(), input,
998 rewriter.replaceOp(op, input);
1006LogicalResult UnionCreateOp::verify() {
1009 return TypeSwitch<Type, LogicalResult>(getType())
1010 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1011 auto members = type.getMembers();
1012 auto resultType = getType();
1014 for (
const auto &member : members)
1015 if (member.name == fieldName && member.type == resultType)
1017 emitOpError(
"input type must match the union field type");
1020 .Default([
this](
auto &) {
1021 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1030LogicalResult UnionExtractOp::verify() {
1033 return TypeSwitch<Type, LogicalResult>(getInput().getType())
1034 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1035 auto members = type.getMembers();
1037 auto resultType = getType();
1038 for (
const auto &member : members)
1039 if (member.name == fieldName && member.type == resultType)
1041 emitOpError(
"result type must match the union field type");
1044 .Default([
this](
auto &) {
1045 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1054LogicalResult UnionExtractRefOp::verify() {
1057 return TypeSwitch<Type, LogicalResult>(getInput().getType().getNestedType())
1058 .Case<UnionType, UnpackedUnionType>([
this](
auto &type) {
1059 auto members = type.getMembers();
1061 auto resultType = getType().getNestedType();
1062 for (
const auto &member : members)
1063 if (member.name == fieldName && member.type == resultType)
1065 emitOpError(
"result type must match the union field type");
1068 .Default([
this](
auto &) {
1069 emitOpError(
"input type must be UnionType or UnpackedUnionType");
1078LogicalResult YieldOp::verify() {
1080 auto *parentOp = getOperation()->getParentOp();
1081 if (
auto cond = dyn_cast<ConditionalOp>(parentOp)) {
1082 expType = cond.getType();
1083 }
else if (
auto varOp = dyn_cast<GlobalVariableOp>(parentOp)) {
1084 expType = varOp.getType();
1086 llvm_unreachable(
"all in ParentOneOf handled");
1089 auto actType = getOperand().getType();
1090 if (expType != actType) {
1091 return emitOpError() <<
"yields " << actType <<
", but parent expects "
1101OpFoldResult ConversionOp::fold(FoldAdaptor adaptor) {
1103 if (getInput().getType() == getResult().getType())
1107 auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput());
1108 auto fromIntType = dyn_cast<IntType>(getInput().getType());
1109 auto toIntType = dyn_cast<IntType>(getResult().getType());
1110 if (intInput && fromIntType && toIntType &&
1111 fromIntType.getWidth() == toIntType.getWidth()) {
1114 if (toIntType.getDomain() == Domain::FourValued)
1119 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1129OpFoldResult LogicToIntOp::fold(FoldAdaptor adaptor) {
1131 if (
auto reverseOp = getInput().getDefiningOp<IntToLogicOp>())
1132 return reverseOp.getInput();
1136 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1137 return FVIntegerAttr::get(getContext(), intInput.getValue().toAPInt(
false));
1146OpFoldResult IntToLogicOp::fold(FoldAdaptor adaptor) {
1151 if (
auto intInput = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1161OpFoldResult TimeToLogicOp::fold(FoldAdaptor adaptor) {
1163 if (
auto reverseOp = getInput().getDefiningOp<LogicToTimeOp>())
1164 return reverseOp.getInput();
1167 if (
auto attr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput()))
1168 return FVIntegerAttr::get(getContext(), attr.getValue());
1177OpFoldResult LogicToTimeOp::fold(FoldAdaptor adaptor) {
1179 if (
auto reverseOp = getInput().getDefiningOp<TimeToLogicOp>())
1180 return reverseOp.getInput();
1183 if (
auto attr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput()))
1184 return IntegerAttr::get(getContext(), APSInt(attr.getValue().toAPInt(
false),
1194OpFoldResult TruncOp::fold(FoldAdaptor adaptor) {
1196 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1197 auto width = getType().getWidth();
1198 return FVIntegerAttr::get(getContext(), intAttr.getValue().trunc(width));
1208OpFoldResult ZExtOp::fold(FoldAdaptor adaptor) {
1210 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1211 auto width = getType().getWidth();
1212 return FVIntegerAttr::get(getContext(), intAttr.getValue().zext(width));
1222OpFoldResult SExtOp::fold(FoldAdaptor adaptor) {
1224 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getInput())) {
1225 auto width = getType().getWidth();
1226 return FVIntegerAttr::get(getContext(), intAttr.getValue().sext(width));
1236OpFoldResult BoolCastOp::fold(FoldAdaptor adaptor) {
1238 if (getInput().getType() == getResult().getType())
1247bool BlockingAssignOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1249bool BlockingAssignOp::storesTo(
const MemorySlot &slot) {
1250 return getDst() == slot.ptr;
1253Value BlockingAssignOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1255 const DataLayout &dataLayout) {
1259bool BlockingAssignOp::canUsesBeRemoved(
1260 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1261 SmallVectorImpl<OpOperand *> &newBlockingUses,
1262 const DataLayout &dataLayout) {
1264 if (blockingUses.size() != 1)
1266 Value blockingUse = (*blockingUses.begin())->
get();
1267 return blockingUse == slot.ptr && getDst() == slot.ptr &&
1268 getSrc() != slot.ptr && getSrc().getType() == slot.elemType;
1271DeletionKind BlockingAssignOp::removeBlockingUses(
1272 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
1273 OpBuilder &builder, Value reachingDefinition,
1274 const DataLayout &dataLayout) {
1275 return DeletionKind::Delete;
1282bool ReadOp::loadsFrom(
const MemorySlot &slot) {
1283 return getInput() == slot.ptr;
1286bool ReadOp::storesTo(
const MemorySlot &slot) {
return false; }
1288Value ReadOp::getStored(
const MemorySlot &slot, OpBuilder &builder,
1289 Value reachingDef,
const DataLayout &dataLayout) {
1290 llvm_unreachable(
"getStored should not be called on ReadOp");
1293bool ReadOp::canUsesBeRemoved(
const MemorySlot &slot,
1294 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1295 SmallVectorImpl<OpOperand *> &newBlockingUses,
1296 const DataLayout &dataLayout) {
1298 if (blockingUses.size() != 1)
1300 Value blockingUse = (*blockingUses.begin())->
get();
1301 return blockingUse == slot.ptr && getOperand() == slot.ptr &&
1302 getResult().getType() == slot.elemType;
1306ReadOp::removeBlockingUses(
const MemorySlot &slot,
1307 const SmallPtrSetImpl<OpOperand *> &blockingUses,
1308 OpBuilder &builder, Value reachingDefinition,
1309 const DataLayout &dataLayout) {
1310 getResult().replaceAllUsesWith(reachingDefinition);
1311 return DeletionKind::Delete;
1320 auto lhsValue = dyn_cast_or_null<FVIntegerAttr>(lhs);
1321 if (lhsValue && lhsValue.getValue() == 1)
1324 auto rhsValue = dyn_cast_or_null<FVIntegerAttr>(rhs);
1325 if (rhsValue && rhsValue.getValue().isZero())
1326 return FVIntegerAttr::get(ctxt,
1327 FVInt(rhsValue.getValue().getBitWidth(), 1));
1332OpFoldResult PowSOp::fold(FoldAdaptor adaptor) {
1336LogicalResult PowSOp::canonicalize(PowSOp op, PatternRewriter &rewriter) {
1337 Location loc = op.getLoc();
1338 auto intType = cast<IntType>(op.getRhs().getType());
1339 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1340 if (baseOp.getValue() == 2) {
1341 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1342 Value constZero = ConstantOp::create(rewriter, loc, intType, 0);
1343 Value shift = ShlOp::create(rewriter, loc, constOne, op.getRhs());
1344 Value isNegative = SltOp::create(rewriter, loc, op.getRhs(), constZero);
1345 auto condOp = rewriter.replaceOpWithNewOp<ConditionalOp>(
1346 op, op.getLhs().getType(), isNegative);
1347 Block *thenBlock = rewriter.createBlock(&condOp.getTrueRegion());
1348 rewriter.setInsertionPointToStart(thenBlock);
1349 YieldOp::create(rewriter, loc, constZero);
1350 Block *elseBlock = rewriter.createBlock(&condOp.getFalseRegion());
1351 rewriter.setInsertionPointToStart(elseBlock);
1352 YieldOp::create(rewriter, loc, shift);
1364OpFoldResult PowUOp::fold(FoldAdaptor adaptor) {
1368LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) {
1369 Location loc = op.getLoc();
1370 auto intType = cast<IntType>(op.getRhs().getType());
1371 if (
auto baseOp = op.getLhs().getDefiningOp<ConstantOp>()) {
1372 if (baseOp.getValue() == 2) {
1373 Value constOne = ConstantOp::create(rewriter, loc, intType, 1);
1374 rewriter.replaceOpWithNewOp<ShlOp>(op, constOne, op.getRhs());
1386OpFoldResult SubOp::fold(FoldAdaptor adaptor) {
1387 if (
auto intAttr = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs()))
1388 if (intAttr.getValue().isZero())
1398OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
1399 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1400 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1402 return FVIntegerAttr::get(getContext(), lhs.getValue() * rhs.getValue());
1410OpFoldResult DivUOp::fold(FoldAdaptor adaptor) {
1411 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1412 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1414 return FVIntegerAttr::get(getContext(),
1415 lhs.getValue().udiv(rhs.getValue()));
1423OpFoldResult DivSOp::fold(FoldAdaptor adaptor) {
1424 auto lhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getLhs());
1425 auto rhs = dyn_cast_or_null<FVIntegerAttr>(adaptor.getRhs());
1427 return FVIntegerAttr::get(getContext(),
1428 lhs.getValue().sdiv(rhs.getValue()));
1436LogicalResult ClassDeclOp::verify() {
1437 mlir::Region &body = getBody();
1439 return mlir::success();
1441 auto &block = body.front();
1442 for (mlir::Operation &op : block) {
1445 if (llvm::isa<circt::moore::ClassPropertyDeclOp,
1446 circt::moore::ClassMethodDeclOp>(&op))
1449 return emitOpError()
1450 <<
"body may only contain 'moore.class.propertydecl' operations";
1452 return mlir::success();
1455LogicalResult ClassNewOp::verify() {
1458 auto handleTy = cast<ClassHandleType>(getResult().getType());
1459 mlir::SymbolRefAttr classSym = handleTy.getClassSym();
1461 return emitOpError(
"result type is missing a class symbol");
1464 mlir::Operation *sym =
1465 mlir::SymbolTable::lookupNearestSymbolFrom(getOperation(), classSym);
1467 return emitOpError(
"referenced class symbol `")
1468 << classSym <<
"` was not found";
1470 if (!llvm::isa<ClassDeclOp>(sym))
1471 return emitOpError(
"symbol `")
1472 << classSym <<
"` does not name a `moore.class.classdecl`";
1474 return mlir::success();
1477void ClassNewOp::getEffects(
1478 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1481 effects.emplace_back(MemoryEffects::Allocate::get());
1485ClassUpcastOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1487 auto srcTy = dyn_cast<ClassHandleType>(getOperand().getType());
1489 return emitOpError() <<
"operand must be !moore.class<...>; got "
1490 << getOperand().getType();
1492 auto dstTy = dyn_cast<ClassHandleType>(getResult().getType());
1494 return emitOpError() <<
"result must be !moore.class<...>; got "
1495 << getResult().getType();
1500 auto *op = getOperation();
1503 symbolTable.lookupNearestSymbolFrom(op, srcTy.getClassSym());
1505 symbolTable.lookupNearestSymbolFrom(op, dstTy.getClassSym());
1506 if (!srcDeclOp || !dstDeclOp)
1507 return emitOpError() <<
"failed to resolve class symbol(s): src="
1508 << srcTy.getClassSym()
1509 <<
", dst=" << dstTy.getClassSym();
1511 auto srcDecl = dyn_cast<ClassDeclOp>(srcDeclOp);
1512 auto dstDecl = dyn_cast<ClassDeclOp>(dstDeclOp);
1513 if (!srcDecl || !dstDecl)
1514 return emitOpError()
1515 <<
"symbol(s) do not name `moore.class.classdecl` ops: src="
1516 << srcTy.getClassSym() <<
", dst=" << dstTy.getClassSym();
1523 auto baseSym = cur.getBaseAttr();
1527 auto *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1528 cur = llvm::dyn_cast_or_null<ClassDeclOp>(baseOp);
1531 return emitOpError() <<
"cannot upcast from " << srcTy.getClassSym() <<
" to "
1532 << dstTy.getClassSym()
1533 <<
" (destination is not a base class)";
1537ClassPropertyRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1539 Type instTy = getInstance().getType();
1540 auto handleTy = dyn_cast<moore::ClassHandleType>(instTy);
1542 return emitOpError() <<
"instance must be a !moore.class<@C> value, got "
1546 SymbolRefAttr classSym = handleTy.getClassSym();
1548 return emitOpError(
"instance type is missing a class symbol");
1552 symbolTable.lookupNearestSymbolFrom(getOperation(), classSym);
1554 return emitOpError(
"referenced class symbol `")
1555 << classSym <<
"` was not found";
1556 auto classDecl = dyn_cast<ClassDeclOp>(clsSym);
1558 return emitOpError(
"symbol `")
1559 << classSym <<
"` does not name a `moore.class.classdecl`";
1562 FlatSymbolRefAttr fieldSym = getPropertyAttr();
1564 return emitOpError(
"missing field symbol");
1566 Operation *fldSym = symbolTable.lookupSymbolIn(classDecl, fieldSym.getAttr());
1568 return emitOpError(
"no field `") << fieldSym <<
"` in class " << classSym;
1570 auto fieldDecl = dyn_cast<ClassPropertyDeclOp>(fldSym);
1572 return emitOpError(
"symbol `")
1573 << fieldSym <<
"` is not a `moore.class.propertydecl`";
1576 auto resRefTy = cast<RefType>(getPropertyRef().getType());
1578 return emitOpError(
"result must be a !moore.ref<T>");
1580 Type expectedElemTy = fieldDecl.getPropertyType();
1581 if (resRefTy.getNestedType() != expectedElemTy)
1582 return emitOpError(
"result element type (")
1583 << resRefTy.getNestedType() <<
") does not match field type ("
1584 << expectedElemTy <<
")";
1590VTableLoadMethodOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1591 Operation *op = getOperation();
1593 auto object = getObject();
1594 auto implSym =
object.getType().getClassSym();
1597 Operation *implOp = symbolTable.lookupNearestSymbolFrom(op, implSym);
1599 return emitOpError() <<
"implementing class " << implSym <<
" not found";
1600 auto implClass = cast<moore::ClassDeclOp>(implOp);
1602 StringAttr methodName = getMethodSymAttr().getLeafReference();
1603 if (!methodName || methodName.getValue().empty())
1604 return emitOpError() <<
"empty method name";
1606 moore::ClassDeclOp cursor = implClass;
1607 Operation *methodDeclOp =
nullptr;
1610 while (cursor && !methodDeclOp) {
1611 methodDeclOp = symbolTable.lookupSymbolIn(cursor, methodName);
1614 SymbolRefAttr baseSym = cursor.getBaseAttr();
1617 Operation *baseOp = symbolTable.lookupNearestSymbolFrom(op, baseSym);
1618 cursor = baseOp ? cast<moore::ClassDeclOp>(baseOp) : moore::ClassDeclOp();
1622 return emitOpError() <<
"no method `" << methodName <<
"` found in "
1623 << implClass.getSymName() <<
" or its bases";
1626 auto methodDecl = dyn_cast<moore::ClassMethodDeclOp>(methodDeclOp);
1628 return emitOpError() <<
"`" << methodName
1629 <<
"` is not a method declaration";
1632 auto resFnTy = cast<FunctionType>(getResult().getType());
1633 auto declFnTy = cast<FunctionType>(methodDecl.getFunctionType());
1634 if (resFnTy != declFnTy)
1635 return emitOpError() <<
"result type " << resFnTy
1636 <<
" does not match method erased ABI " << declFnTy;
1641LogicalResult VTableOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1642 Operation *self = getOperation();
1645 SymbolRefAttr name = getSymNameAttr();
1647 return emitOpError(
"requires 'sym_name' SymbolRefAttr");
1650 Operation *rootDef = symbolTable.lookupNearestSymbolFrom(
1651 self, SymbolRefAttr::get(name.getRootReference()));
1653 return emitOpError() <<
"cannot resolve root class symbol '"
1654 << name.getRootReference() <<
"' for sym_name "
1657 if (!isa<ClassDeclOp>(rootDef))
1658 return emitOpError()
1659 <<
"root of sym_name must name a 'moore.class.classdecl', got "
1666LogicalResult VTableOp::verifyRegions() {
1668 for (Operation &op : getBody().front()) {
1669 if (!isa<VTableOp, VTableEntryOp>(op))
1671 "body may only contain 'moore.vtable' or 'moore.vtable_entry' ops");
1673 return mlir::success();
1677VTableEntryOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1678 Operation *self = getOperation();
1682 SymbolRefAttr target = getTargetAttr();
1684 symbolTable.lookupNearestSymbolFrom<func::FuncOp>(self, target);
1686 return emitOpError()
1687 <<
"cannot resolve target symbol to a function operation " << target;
1690 if (!isa<VTableOp>(self->getParentOp()))
1691 return emitOpError(
"must be nested directly inside a 'moore.vtable' op");
1693 Operation *currentOp = self;
1694 VTableOp currentVTable;
1695 bool defined =
false;
1702 while (
auto parentOp = dyn_cast<VTableOp>(currentOp->getParentOp())) {
1703 currentOp = parentOp;
1704 currentVTable = cast<VTableOp>(currentOp);
1706 auto classSymName = currentVTable.getSymName();
1707 ClassDeclOp parentClassDecl =
1708 symbolTable.lookupNearestSymbolFrom<ClassDeclOp>(
1709 parentOp, classSymName.getRootReference());
1710 assert(parentClassDecl &&
"VTableOp must point to a classdeclop");
1712 for (
auto method : parentClassDecl.getBody().getOps<ClassMethodDeclOp>()) {
1714 if (!method.getImpl())
1718 if (method.getSymName() ==
getName() && method.getImplAttr() == target)
1726 else if (method.getSymName() ==
getName() &&
1727 method.getImplAttr() != target && defined)
1728 return emitOpError() <<
"Target " << target
1729 <<
" should be overridden by " << classSymName;
1733 return emitOpError()
1734 <<
"Parent class does not point to any implementation!";
1744#define GET_OP_CLASSES
1745#include "circt/Dialect/Moore/Moore.cpp.inc"
1746#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