21 #include "mlir/IR/BuiltinAttributes.h"
22 #include "mlir/IR/ImplicitLocOpBuilder.h"
23 #include "mlir/IR/Threading.h"
24 #include "mlir/IR/Visitors.h"
25 #include "mlir/Pass/Pass.h"
26 #include "llvm/ADT/ArrayRef.h"
27 #include "llvm/ADT/STLExtras.h"
28 #include "llvm/ADT/SmallVector.h"
29 #include "llvm/Support/ErrorHandling.h"
33 #define GEN_PASS_DEF_VBTOBV
34 #include "circt/Dialect/FIRRTL/Passes.h.inc"
38 using namespace circt;
39 using namespace firrtl;
46 class Visitor :
public FIRRTLVisitor<Visitor, LogicalResult> {
48 explicit Visitor(MLIRContext *);
50 LogicalResult visit(FModuleOp);
56 LogicalResult visitUnhandledOp(Operation *);
58 LogicalResult visitInvalidOp(Operation *op) {
59 return op->emitError(
"invalid operation operation");
62 template <
typename Op>
63 void emitExplodedConnect(ImplicitLocOpBuilder &, Type, ArrayRef<Value>,
65 Value emitBundleCreate(ImplicitLocOpBuilder &, Type, ArrayRef<Value>);
66 template <
typename Op>
67 void handleConnect(Op);
69 LogicalResult visitStmt(ConnectOp);
70 LogicalResult visitStmt(MatchingConnectOp);
72 LogicalResult visitExpr(AggregateConstantOp);
73 LogicalResult visitExpr(VectorCreateOp);
74 LogicalResult visitExpr(SubfieldOp);
75 LogicalResult visitExpr(SubindexOp);
76 LogicalResult visitExpr(SubaccessOp);
77 LogicalResult visitExpr(RefSubOp);
78 LogicalResult visitExpr(RefResolveOp);
86 Attribute convertConstant(Type, Attribute);
87 Attribute convertVectorConstant(FVectorType, ArrayAttr);
88 Attribute convertBundleConstant(BundleType, ArrayAttr);
89 Attribute convertBundleInVectorConstant(BundleType, ArrayRef<Attribute>);
92 void explodeFieldID(Type, uint64_t,
93 SmallVectorImpl<std::pair<Type, uint64_t>> &);
94 void fixAnnotation(Type, Type, DictionaryAttr, SmallVectorImpl<Attribute> &);
95 ArrayAttr fixAnnotations(Type, Type, ArrayAttr);
98 void explode(Value, SmallVectorImpl<Value> &);
99 SmallVector<Value> explode(Value);
101 void explodeRef(Value, SmallVectorImpl<Value> &);
103 std::pair<SmallVector<Value>,
bool> fixOperand(Value);
107 Value fixROperand(Value);
109 std::pair<SmallVector<Value>,
bool> fixRefOperand(Value);
112 Value sinkVecDimIntoOperands(ImplicitLocOpBuilder &,
FIRRTLBaseType,
113 const SmallVectorImpl<Value> &);
116 Value getSubfield(Value,
unsigned);
117 Value getSubindex(Value,
unsigned);
118 Value getSubaccess(Operation *, Value, Value);
119 Value getRefSub(Value,
unsigned);
121 MLIRContext *context;
122 SmallVector<Operation *> toDelete;
127 DenseMap<Value, Value> valueMap;
130 DenseMap<FIRRTLType, FIRRTLType> typeMap;
133 DenseMap<std::tuple<Value, unsigned>, Value> subfieldCache;
134 DenseMap<std::tuple<Value, unsigned>, Value> subindexCache;
135 DenseMap<std::tuple<Operation *, Value, Value>, Value> subaccessCache;
136 DenseMap<std::tuple<Value, unsigned>, Value> refSubCache;
140 Visitor::Visitor(MLIRContext *context) : context(context) {}
148 SmallVector<unsigned> &dimensions) {
149 if (
auto vectorType = type_dyn_cast<FVectorType>(type); vectorType) {
150 dimensions.push_back(vectorType.getNumElements());
151 auto converted =
convertType(vectorType.getElementType(), dimensions);
152 dimensions.pop_back();
155 if (
auto bundleType = type_dyn_cast<BundleType>(type); bundleType) {
156 SmallVector<BundleType::BundleElement> elements;
157 for (
auto element : bundleType.getElements()) {
158 elements.push_back(BundleType::BundleElement(
159 element.name, element.isFlip,
convertType(element.type, dimensions)));
163 for (
auto size : llvm::reverse(dimensions))
169 auto cached = typeMap.lookup(type);
171 return type_cast<FIRRTLBaseType>(cached);
173 SmallVector<unsigned> dimensions;
176 typeMap.insert({type, converted});
181 auto cached = typeMap.lookup(type);
183 return type_cast<RefType>(cached);
185 type.getForceable(), type.getLayer());
186 typeMap.insert({type, converted});
191 auto cached = typeMap.lookup(type);
193 return type_cast<FIRRTLType>(cached);
194 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type))
196 if (
auto refType = type_dyn_cast<RefType>(type))
202 if (
auto firrtlType = type_dyn_cast<FIRRTLType>(type))
212 void Visitor::explodeFieldID(
213 Type type, uint64_t fieldID,
214 SmallVectorImpl<std::pair<Type, uint64_t>> &fields) {
215 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
216 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
217 auto eltType = bundleType.getElementType(i);
218 auto eltID = fieldID + bundleType.getFieldID(i);
219 explodeFieldID(eltType, eltID, fields);
223 fields.emplace_back(type, fieldID);
226 void Visitor::fixAnnotation(Type oldType, Type newType, DictionaryAttr annoAttr,
227 SmallVectorImpl<Attribute> &newAnnos) {
229 auto fieldID = anno.getFieldID();
234 newAnnos.push_back(anno.getAttr());
238 SmallVector<uint32_t> bundleAccesses;
239 SmallVector<uint32_t> vectorAccesses;
240 while (fieldID != 0) {
241 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
242 auto [index, subID] = bundleType.getIndexAndSubfieldID(fieldID);
243 bundleAccesses.push_back(index);
244 oldType = bundleType.getElementType(index);
248 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
249 auto [index, subID] = vectorType.getIndexAndSubfieldID(fieldID);
250 vectorAccesses.push_back(index);
251 oldType = vectorType.getElementType();
255 llvm_unreachable(
"non-zero field ID can only be used on aggregate types");
259 for (
auto index : bundleAccesses) {
260 auto bundleType = type_cast<BundleType>(newType);
261 newID += bundleType.getFieldID(index);
262 newType = bundleType.getElementType(index);
265 SmallVector<std::pair<Type, uint64_t>> fields;
266 if (type_isa<BundleType>(newType) && !vectorAccesses.empty()) {
267 explodeFieldID(newType, newID, fields);
269 fields.emplace_back(newType, newID);
273 for (
auto [type, fieldID] : fields) {
274 for (
auto index : vectorAccesses) {
275 auto vectorType = type_cast<FVectorType>(type);
276 type = vectorType.getElementType();
277 fieldID += vectorType.getFieldID(index);
280 newAnnos.push_back(anno.getAttr());
284 ArrayAttr Visitor::fixAnnotations(Type oldType, Type newType, ArrayAttr annos) {
285 SmallVector<Attribute> newAnnos;
286 for (
auto anno : cast<ArrayAttr>(annos).getAsRange<DictionaryAttr>())
287 fixAnnotation(oldType, newType, anno, newAnnos);
295 Value Visitor::getSubfield(Value input,
unsigned index) {
296 Value &result = subfieldCache[{input, index}];
300 OpBuilder builder(context);
301 builder.setInsertionPointAfterValue(input);
302 result = builder.create<SubfieldOp>(input.getLoc(), input, index);
306 Value Visitor::getSubindex(Value input,
unsigned index) {
307 auto &result = subindexCache[{input, index}];
311 OpBuilder builder(context);
312 builder.setInsertionPointAfterValue(input);
313 result = builder.create<SubindexOp>(input.getLoc(), input, index);
317 Value Visitor::getSubaccess(Operation *place, Value input, Value index) {
318 auto &result = subaccessCache[{place, input, index}];
321 OpBuilder builder(place);
322 result = builder.create<SubaccessOp>(input.getLoc(), input, index);
326 Value Visitor::getRefSub(Value input,
unsigned index) {
327 auto &result = refSubCache[{input, index}];
330 OpBuilder builder(context);
331 builder.setInsertionPointAfterValue(input);
332 result = builder.create<RefSubOp>(input.getLoc(), input, index);
341 void Visitor::explodeRef(Value value, SmallVectorImpl<Value> &output) {
342 auto underlyingType = type_cast<RefType>(value.getType()).getType();
343 if (
auto bundleType = type_dyn_cast<BundleType>(underlyingType)) {
344 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
345 OpBuilder builder(context);
346 builder.setInsertionPointAfterValue(value);
347 auto field = builder.create<RefSubOp>(value.getLoc(), value, i);
348 explodeRef(field, output);
352 output.push_back(value);
355 std::pair<SmallVector<Value>,
bool> Visitor::fixRefOperand(Value value) {
356 SmallVector<unsigned> bundleAccesses;
357 SmallVector<unsigned> vectorAccesses;
361 Operation *op = value.getDefiningOp();
364 if (
auto refSubOp = dyn_cast<RefSubOp>(op)) {
365 value = refSubOp.getInput();
366 auto type = type_cast<RefType>(value.getType()).getType();
367 if (type_isa<BundleType>(type))
368 bundleAccesses.push_back(refSubOp.getIndex());
369 else if (type_isa<FVectorType>(type))
370 vectorAccesses.push_back(refSubOp.getIndex());
372 refSubOp->emitError(
"unknown aggregate type");
380 value = valueMap[value];
384 for (
auto index : llvm::reverse(bundleAccesses)) {
385 value = getRefSub(value, index);
392 SmallVector<Value> values;
393 bool exploded =
false;
394 if (type_isa<BundleType>(type_cast<RefType>(value.getType()).getType()) &&
395 !vectorAccesses.empty()) {
396 explodeRef(value, values);
399 values.push_back(value);
404 for (
auto &value : values) {
405 for (
auto index : llvm::reverse(vectorAccesses)) {
406 value = getRefSub(value, index);
410 return {values, exploded};
418 void Visitor::explode(Value value, SmallVectorImpl<Value> &output) {
419 auto type = value.getType();
420 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
421 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
422 auto field = getSubfield(value, i);
423 explode(field, output);
427 output.push_back(value);
430 SmallVector<Value> Visitor::explode(Value value) {
431 auto output = SmallVector<Value>();
432 explode(value, output);
437 std::pair<SmallVector<Value>,
bool> Visitor::fixOperand(Value value) {
438 auto type = value.getType();
442 if (type_isa<RefType>(type))
443 return fixRefOperand(value);
445 SmallVector<SubfieldOp> bundleAccesses;
446 SmallVector<Operation *> vectorAccesses;
452 Operation *op = value.getDefiningOp();
455 if (
auto subfieldOp = dyn_cast<SubfieldOp>(op)) {
456 value = subfieldOp.getInput();
457 bundleAccesses.push_back(subfieldOp);
460 if (
auto subindexOp = dyn_cast<SubindexOp>(op)) {
461 value = subindexOp.getInput();
462 vectorAccesses.push_back(subindexOp);
465 if (
auto subaccessOp = dyn_cast<SubaccessOp>(op)) {
466 value = subaccessOp.getInput();
467 vectorAccesses.push_back(subaccessOp);
475 value = valueMap[value];
476 assert(value &&
"canonical storage location must have been converted");
480 for (
auto subfieldOp : llvm::reverse(bundleAccesses))
481 value = getSubfield(value, subfieldOp.getFieldIndex());
486 SmallVector<Value> values;
487 bool exploded =
false;
489 if (type_isa<BundleType>(value.getType()) && !vectorAccesses.empty()) {
490 explode(value, values);
493 values.push_back(value);
498 for (
auto &value : values) {
499 for (
auto *op : llvm::reverse(vectorAccesses)) {
500 if (
auto subindexOp = dyn_cast<SubindexOp>(op)) {
501 value = getSubindex(value, subindexOp.getIndex());
504 if (
auto subaccessOp = dyn_cast<SubaccessOp>(op)) {
505 auto index = fixROperand(subaccessOp.getIndex());
506 value = getSubaccess(subaccessOp, value, index);
512 return {values, exploded};
520 Value Visitor::fixROperand(Value operand) {
521 auto [values, exploded] = fixOperand(operand);
523 return values.front();
527 ImplicitLocOpBuilder builder(operand.getLoc(), context);
528 builder.setInsertionPointAfterValue(operand);
529 return emitBundleCreate(builder, newType, values);
536 LogicalResult Visitor::visitUnhandledOp(Operation *op) {
537 ImplicitLocOpBuilder builder(op->getLoc(), op);
538 bool changed =
false;
543 SmallVector<Value> newOperands;
544 for (
auto oldOperand : op->getOperands()) {
545 auto newOperand = fixROperand(oldOperand);
546 changed |= (oldOperand != newOperand);
547 newOperands.push_back(newOperand);
552 SmallVector<Type> newTypes;
553 for (
auto oldResult : op->getResults()) {
554 auto oldType = oldResult.getType();
556 changed |= oldType != newType;
557 newTypes.push_back(newType);
561 auto *newOp = builder.clone(*op);
562 newOp->setOperands(newOperands);
563 for (
size_t i = 0, e = op->getNumResults(); i < e; ++i) {
564 auto newResult = newOp->getResult(i);
565 newResult.setType(newTypes[i]);
566 valueMap[op->getResult(i)] = newResult;
570 if (
auto portAnnos = op->getAttrOfType<ArrayAttr>(
"portAnnotations")) {
573 SmallVector<Attribute> newPortAnnos;
574 for (
unsigned i = 0, e = portAnnos.size(); i < e; ++i) {
575 auto oldType = op->getResult(i).getType();
576 auto newType = newTypes[i];
577 newPortAnnos.push_back(
578 fixAnnotations(oldType, newType, cast<ArrayAttr>(portAnnos[i])));
580 newOp->setAttr(
"portAnnotations",
ArrayAttr::get(context, newPortAnnos));
581 }
else if (newOp->getNumResults() == 1) {
586 if (
auto annos = newOp->getAttrOfType<ArrayAttr>(
"annotations")) {
587 auto oldType = op->getResult(0).getType();
588 auto newType = newTypes[0];
589 auto newAnnos = fixAnnotations(oldType, newType, annos);
594 toDelete.push_back(op);
600 for (
auto result : op->getResults())
601 valueMap[result] = result;
604 for (
auto ®ion : op->getRegions())
605 for (
auto &block : region.getBlocks())
606 for (
auto &op : block)
607 if (failed(dispatchVisitor(&op)))
617 template <
typename Op>
618 void Visitor::emitExplodedConnect(ImplicitLocOpBuilder &builder, Type type,
619 ArrayRef<Value> lhs, ArrayRef<Value> rhs) {
620 assert(lhs.size() == rhs.size() &&
621 "Something went wrong exploding the elements");
622 const auto *lhsIt = lhs.begin();
623 const auto *rhsIt = rhs.begin();
625 auto explodeConnect = [&](
auto self, Type type,
bool flip =
false) ->
void {
626 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
627 for (
auto &element : bundleType) {
628 self(
self, element.type,
flip ^ element.isFlip);
636 builder.create<Op>(lhs, rhs);
638 explodeConnect(explodeConnect, type);
641 Value Visitor::emitBundleCreate(ImplicitLocOpBuilder &builder, Type type,
642 ArrayRef<Value> values) {
643 auto *it = values.begin();
644 auto convert = [&](
auto self, Type type) -> Value {
645 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
646 SmallVector<Value> fields;
647 for (
auto element : bundleType.getElements()) {
648 fields.push_back(
self(
self, element.type));
650 return builder.create<BundleCreateOp>(type, fields);
654 return convert(convert, type);
657 template <
typename Op>
658 void Visitor::handleConnect(Op op) {
659 ImplicitLocOpBuilder builder(op.getLoc(), op);
660 auto oldLhs = op.getDest();
661 auto oldRhs = op.getSrc();
663 auto oldType = type_cast<FIRRTLType>(oldLhs.getType());
666 auto [lhs, lhsExploded] = fixOperand(oldLhs);
667 auto [rhs, rhsExploded] = fixOperand(oldRhs);
669 if (!lhsExploded && !rhsExploded && oldLhs == lhs[0] && oldRhs == rhs[0])
674 emitExplodedConnect<Op>(builder, type, lhs, rhs);
676 emitExplodedConnect<Op>(builder, type, lhs, explode(rhs[0]));
680 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
681 baseType && baseType.isPassive()) {
682 builder.create<Op>(lhs[0], emitBundleCreate(builder, type, rhs));
684 emitExplodedConnect<Op>(builder, type, explode(lhs[0]), rhs);
687 builder.create<Op>(lhs[0], rhs[0]);
691 toDelete.push_back(op);
694 LogicalResult Visitor::visitStmt(ConnectOp op) {
699 LogicalResult Visitor::visitStmt(MatchingConnectOp op) {
708 Attribute Visitor::convertBundleInVectorConstant(BundleType type,
709 ArrayRef<Attribute> fields) {
710 auto numBundleFields = type.getNumElements();
711 SmallVector<SmallVector<Attribute>> newBundleFields;
712 newBundleFields.resize(numBundleFields);
713 for (
auto bundle : fields) {
714 auto subfields = cast<ArrayAttr>(bundle);
715 for (
size_t i = 0; i < numBundleFields; ++i) {
716 newBundleFields[i].push_back(subfields[i]);
720 SmallVector<Attribute> newFieldAttrs;
721 for (
auto &newBundleField : newBundleFields) {
728 Attribute Visitor::convertVectorConstant(FVectorType oldType,
729 ArrayAttr oldElements) {
730 auto oldElementType = oldType.getElementType();
733 if (oldElementType == newElementType)
734 if (
auto bundleElementType = type_dyn_cast<BundleType>(oldElementType))
735 return convertBundleInVectorConstant(bundleElementType,
736 oldElements.getValue());
738 SmallVector<Attribute> newElements;
739 for (
auto oldElement : oldElements) {
740 newElements.push_back(convertConstant(oldElementType, oldElement));
743 auto bundleType = type_cast<BundleType>(newElementType);
744 return convertBundleInVectorConstant(bundleType, newElements);
748 Attribute Visitor::convertBundleConstant(BundleType type, ArrayAttr fields) {
749 SmallVector<Attribute> converted;
750 auto elements = type.getElements();
751 for (
size_t i = 0, e = elements.size(); i < e; ++i) {
752 converted.push_back(convertConstant(elements[i].type, fields[i]));
758 Attribute Visitor::convertConstant(Type type, Attribute value) {
759 if (
auto bundleType = type_dyn_cast<BundleType>(type))
760 return convertBundleConstant(bundleType, cast<ArrayAttr>(value));
762 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
763 return convertVectorConstant(vectorType, cast<ArrayAttr>(value));
768 LogicalResult Visitor::visitExpr(AggregateConstantOp op) {
769 auto oldValue = op.getResult();
771 auto oldType = oldValue.getType();
773 if (oldType == newType) {
774 valueMap[oldValue] = oldValue;
778 auto fields = cast<ArrayAttr>(convertConstant(oldType, op.getFields()));
780 OpBuilder builder(op);
782 builder.create<AggregateConstantOp>(op.getLoc(), newType, fields);
784 valueMap[oldValue] = newOp.getResult();
785 toDelete.push_back(op);
795 Value Visitor::sinkVecDimIntoOperands(ImplicitLocOpBuilder &builder,
797 const SmallVectorImpl<Value> &values) {
798 auto length = values.size();
799 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
800 SmallVector<Value> newFields;
801 SmallVector<BundleType::BundleElement> newElements;
802 for (
auto [i, elt] : llvm::enumerate(bundleType)) {
803 SmallVector<Value> subValues;
804 for (
auto v : values)
805 subValues.push_back(getSubfield(v, i));
806 auto newField = sinkVecDimIntoOperands(builder, elt.type, subValues);
807 newFields.push_back(newField);
808 newElements.emplace_back(elt.name,
false,
809 type_cast<FIRRTLBaseType>(newField.getType()));
812 auto newBundle = builder.create<BundleCreateOp>(newType, newFields);
816 return builder.create<VectorCreateOp>(newType, values);
819 LogicalResult Visitor::visitExpr(VectorCreateOp op) {
820 ImplicitLocOpBuilder builder(op.getLoc(), op);
822 auto oldType = op.getType();
825 if (oldType == newType) {
826 auto changed =
false;
827 SmallVector<Value> newFields;
828 for (
auto oldField : op.getFields()) {
829 auto newField = fixROperand(oldField);
830 if (oldField != newField)
832 newFields.push_back(newField);
836 auto result = op.getResult();
837 valueMap[result] = result;
842 builder.create<VectorCreateOp>(op.getLoc(), newType, newFields);
843 valueMap[op.getResult()] = newOp.getResult();
844 toDelete.push_back(op);
849 SmallVector<Value> convertedOldFields;
850 for (
auto oldField : op.getFields()) {
851 auto convertedField = fixROperand(oldField);
852 convertedOldFields.push_back(convertedField);
855 auto value = sinkVecDimIntoOperands(
856 builder,
convertType(oldType.base().getElementType()),
858 valueMap[op.getResult()] = value;
859 toDelete.push_back(op);
867 LogicalResult Visitor::visitExpr(SubfieldOp op) {
868 toDelete.push_back(op);
872 LogicalResult Visitor::visitExpr(SubindexOp op) {
873 toDelete.push_back(op);
877 LogicalResult Visitor::visitExpr(SubaccessOp op) {
878 toDelete.push_back(op);
882 LogicalResult Visitor::visitExpr(RefSubOp op) {
883 toDelete.push_back(op);
891 LogicalResult Visitor::visitExpr(RefResolveOp op) {
892 ImplicitLocOpBuilder builder(op.getLoc(), op);
893 auto [refs, exploded] = fixRefOperand(op.getRef());
896 if (ref == op.getRef()) {
897 valueMap[op.getResult()] = op.getResult();
900 auto value = builder.create<RefResolveOp>(
convertType(op.getType()), ref)
902 valueMap[op.getResult()] = value;
903 toDelete.push_back(op);
908 SmallVector<Value> values;
909 for (
auto ref : refs) {
910 values.push_back(builder
911 .create<RefResolveOp>(
912 type_cast<RefType>(ref.getType()).getType(), ref)
915 auto value = emitBundleCreate(builder, type, values);
916 valueMap[op.getResult()] = value;
917 toDelete.push_back(op);
925 LogicalResult Visitor::visit(FModuleOp op) {
926 BitVector portsToErase(op.getNumPorts() * 2);
928 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
929 auto ports = op.getPorts();
931 for (
auto [index, port] : llvm::enumerate(ports)) {
932 auto oldType = port.type;
934 if (newType == oldType)
937 newPort.type = newType;
939 fixAnnotations(oldType, newType, port.annotations.getArrayAttr()));
940 portsToErase[count + index] =
true;
941 newPorts.push_back({index + 1, newPort});
945 op.insertPorts(newPorts);
948 auto *body = op.getBodyBlock();
949 for (
unsigned i = 0, e = body->getNumArguments(); i < e; ++i) {
950 if (portsToErase[i]) {
951 auto oldArg = body->getArgument(i);
952 auto newArg = body->getArgument(i + 1);
953 valueMap[oldArg] = newArg;
955 auto oldArg = body->getArgument(i);
956 valueMap[oldArg] = oldArg;
960 for (
auto &op : *body) {
961 if (failed(dispatchVisitor(&op)))
965 while (!toDelete.empty())
966 toDelete.pop_back_val()->erase();
967 op.erasePorts(portsToErase);
977 class VBToBVPass :
public circt::firrtl::impl::VBToBVBase<VBToBVPass> {
978 void runOnOperation()
override;
982 void VBToBVPass::runOnOperation() {
983 std::vector<FModuleOp> modules;
984 llvm::append_range(modules, getOperation().getBody().getOps<FModuleOp>());
986 failableParallelForEach(&getContext(), modules, [&](FModuleOp module) {
987 Visitor visitor(&getContext());
988 return visitor.visit(module);
996 return std::make_unique<VBToBVPass>();
assert(baseType &&"element must be base type")
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
This class provides a read-only projection of an annotation.
FIRRTLVisitor allows you to visit all of the expr/stmt/decls with one class declaration.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction flip(Direction direction)
Flip a port direction.
std::unique_ptr< mlir::Pass > createVBToBVPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.