19 #include "mlir/IR/BuiltinAttributes.h"
20 #include "mlir/IR/ImplicitLocOpBuilder.h"
21 #include "mlir/IR/Threading.h"
22 #include "mlir/IR/Visitors.h"
23 #include "mlir/Pass/Pass.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallVector.h"
27 #include "llvm/Support/ErrorHandling.h"
31 #define GEN_PASS_DEF_VBTOBV
32 #include "circt/Dialect/FIRRTL/Passes.h.inc"
36 using namespace circt;
37 using namespace firrtl;
44 class Visitor :
public FIRRTLVisitor<Visitor, LogicalResult> {
46 explicit Visitor(MLIRContext *);
48 LogicalResult visit(FModuleOp);
54 LogicalResult visitUnhandledOp(Operation *);
56 LogicalResult visitInvalidOp(Operation *op) {
57 return op->emitError(
"invalid operation operation");
60 template <
typename Op>
61 void emitExplodedConnect(ImplicitLocOpBuilder &, Type, ArrayRef<Value>,
63 Value emitBundleCreate(ImplicitLocOpBuilder &, Type, ArrayRef<Value>);
64 template <
typename Op>
65 void handleConnect(Op);
67 LogicalResult visitStmt(ConnectOp);
68 LogicalResult visitStmt(MatchingConnectOp);
70 LogicalResult visitExpr(AggregateConstantOp);
71 LogicalResult visitExpr(VectorCreateOp);
72 LogicalResult visitExpr(SubfieldOp);
73 LogicalResult visitExpr(SubindexOp);
74 LogicalResult visitExpr(SubaccessOp);
75 LogicalResult visitExpr(RefSubOp);
76 LogicalResult visitExpr(RefResolveOp);
84 Attribute convertConstant(Type, Attribute);
85 Attribute convertVectorConstant(FVectorType, ArrayAttr);
86 Attribute convertBundleConstant(BundleType, ArrayAttr);
87 Attribute convertBundleInVectorConstant(BundleType, ArrayRef<Attribute>);
90 void explodeFieldID(Type, uint64_t,
91 SmallVectorImpl<std::pair<Type, uint64_t>> &);
92 void fixAnnotation(Type, Type, DictionaryAttr, SmallVectorImpl<Attribute> &);
93 ArrayAttr fixAnnotations(Type, Type, ArrayAttr);
96 void explode(Value, SmallVectorImpl<Value> &);
97 SmallVector<Value> explode(Value);
99 void explodeRef(Value, SmallVectorImpl<Value> &);
101 std::pair<SmallVector<Value>,
bool> fixOperand(Value);
105 Value fixROperand(Value);
107 std::pair<SmallVector<Value>,
bool> fixRefOperand(Value);
110 Value sinkVecDimIntoOperands(ImplicitLocOpBuilder &,
FIRRTLBaseType,
111 const SmallVectorImpl<Value> &);
114 Value getSubfield(Value,
unsigned);
115 Value getSubindex(Value,
unsigned);
116 Value getSubaccess(Operation *, Value, Value);
117 Value getRefSub(Value,
unsigned);
119 MLIRContext *context;
120 SmallVector<Operation *> toDelete;
125 DenseMap<Value, Value> valueMap;
128 DenseMap<FIRRTLType, FIRRTLType> typeMap;
131 DenseMap<std::tuple<Value, unsigned>, Value> subfieldCache;
132 DenseMap<std::tuple<Value, unsigned>, Value> subindexCache;
133 DenseMap<std::tuple<Operation *, Value, Value>, Value> subaccessCache;
134 DenseMap<std::tuple<Value, unsigned>, Value> refSubCache;
138 Visitor::Visitor(MLIRContext *context) : context(context) {}
146 SmallVector<unsigned> &dimensions) {
147 if (
auto vectorType = type_dyn_cast<FVectorType>(type); vectorType) {
148 dimensions.push_back(vectorType.getNumElements());
149 auto converted =
convertType(vectorType.getElementType(), dimensions);
150 dimensions.pop_back();
153 if (
auto bundleType = type_dyn_cast<BundleType>(type); bundleType) {
154 SmallVector<BundleType::BundleElement> elements;
155 for (
auto element : bundleType.getElements()) {
156 elements.push_back(BundleType::BundleElement(
157 element.name, element.isFlip,
convertType(element.type, dimensions)));
161 for (
auto size : llvm::reverse(dimensions))
167 auto cached = typeMap.lookup(type);
169 return type_cast<FIRRTLBaseType>(cached);
171 SmallVector<unsigned> dimensions;
174 typeMap.insert({type, converted});
179 auto cached = typeMap.lookup(type);
181 return type_cast<RefType>(cached);
183 type.getForceable(), type.getLayer());
184 typeMap.insert({type, converted});
189 auto cached = typeMap.lookup(type);
191 return type_cast<FIRRTLType>(cached);
192 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type))
194 if (
auto refType = type_dyn_cast<RefType>(type))
200 if (
auto firrtlType = type_dyn_cast<FIRRTLType>(type))
210 void Visitor::explodeFieldID(
211 Type type, uint64_t fieldID,
212 SmallVectorImpl<std::pair<Type, uint64_t>> &fields) {
213 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
214 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
215 auto eltType = bundleType.getElementType(i);
216 auto eltID = fieldID + bundleType.getFieldID(i);
217 explodeFieldID(eltType, eltID, fields);
221 fields.emplace_back(type, fieldID);
224 void Visitor::fixAnnotation(Type oldType, Type newType, DictionaryAttr annoAttr,
225 SmallVectorImpl<Attribute> &newAnnos) {
227 auto fieldID = anno.getFieldID();
232 newAnnos.push_back(anno.getAttr());
236 SmallVector<uint32_t> bundleAccesses;
237 SmallVector<uint32_t> vectorAccesses;
238 while (fieldID != 0) {
239 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
240 auto [index, subID] = bundleType.getIndexAndSubfieldID(fieldID);
241 bundleAccesses.push_back(index);
242 oldType = bundleType.getElementType(index);
246 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
247 auto [index, subID] = vectorType.getIndexAndSubfieldID(fieldID);
248 vectorAccesses.push_back(index);
249 oldType = vectorType.getElementType();
253 llvm_unreachable(
"non-zero field ID can only be used on aggregate types");
257 for (
auto index : bundleAccesses) {
258 auto bundleType = type_cast<BundleType>(newType);
259 newID += bundleType.getFieldID(index);
260 newType = bundleType.getElementType(index);
263 SmallVector<std::pair<Type, uint64_t>> fields;
264 if (type_isa<BundleType>(newType) && !vectorAccesses.empty()) {
265 explodeFieldID(newType, newID, fields);
267 fields.emplace_back(newType, newID);
271 for (
auto [type, fieldID] : fields) {
272 for (
auto index : vectorAccesses) {
273 auto vectorType = type_cast<FVectorType>(type);
274 type = vectorType.getElementType();
275 fieldID += vectorType.getFieldID(index);
278 newAnnos.push_back(anno.getAttr());
282 ArrayAttr Visitor::fixAnnotations(Type oldType, Type newType, ArrayAttr annos) {
283 SmallVector<Attribute> newAnnos;
284 for (
auto anno : cast<ArrayAttr>(annos).getAsRange<DictionaryAttr>())
285 fixAnnotation(oldType, newType, anno, newAnnos);
293 Value Visitor::getSubfield(Value input,
unsigned index) {
294 Value &result = subfieldCache[{input, index}];
298 OpBuilder builder(context);
299 builder.setInsertionPointAfterValue(input);
300 result = builder.create<SubfieldOp>(input.getLoc(), input, index);
304 Value Visitor::getSubindex(Value input,
unsigned index) {
305 auto &result = subindexCache[{input, index}];
309 OpBuilder builder(context);
310 builder.setInsertionPointAfterValue(input);
311 result = builder.create<SubindexOp>(input.getLoc(), input, index);
315 Value Visitor::getSubaccess(Operation *place, Value input, Value index) {
316 auto &result = subaccessCache[{place, input, index}];
319 OpBuilder builder(place);
320 result = builder.create<SubaccessOp>(input.getLoc(), input, index);
324 Value Visitor::getRefSub(Value input,
unsigned index) {
325 auto &result = refSubCache[{input, index}];
328 OpBuilder builder(context);
329 builder.setInsertionPointAfterValue(input);
330 result = builder.create<RefSubOp>(input.getLoc(), input, index);
339 void Visitor::explodeRef(Value value, SmallVectorImpl<Value> &output) {
340 auto underlyingType = type_cast<RefType>(value.getType()).getType();
341 if (
auto bundleType = type_dyn_cast<BundleType>(underlyingType)) {
342 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
343 OpBuilder builder(context);
344 builder.setInsertionPointAfterValue(value);
345 auto field = builder.create<RefSubOp>(value.getLoc(), value, i);
346 explodeRef(field, output);
350 output.push_back(value);
353 std::pair<SmallVector<Value>,
bool> Visitor::fixRefOperand(Value value) {
354 SmallVector<unsigned> bundleAccesses;
355 SmallVector<unsigned> vectorAccesses;
359 Operation *op = value.getDefiningOp();
362 if (
auto refSubOp = dyn_cast<RefSubOp>(op)) {
363 value = refSubOp.getInput();
364 auto type = type_cast<RefType>(value.getType()).getType();
365 if (type_isa<BundleType>(type))
366 bundleAccesses.push_back(refSubOp.getIndex());
367 else if (type_isa<FVectorType>(type))
368 vectorAccesses.push_back(refSubOp.getIndex());
370 refSubOp->emitError(
"unknown aggregate type");
378 value = valueMap[value];
382 for (
auto index : llvm::reverse(bundleAccesses)) {
383 value = getRefSub(value, index);
390 SmallVector<Value> values;
391 bool exploded =
false;
392 if (type_isa<BundleType>(type_cast<RefType>(value.getType()).getType()) &&
393 !vectorAccesses.empty()) {
394 explodeRef(value, values);
397 values.push_back(value);
402 for (
auto &value : values) {
403 for (
auto index : llvm::reverse(vectorAccesses)) {
404 value = getRefSub(value, index);
408 return {values, exploded};
416 void Visitor::explode(Value value, SmallVectorImpl<Value> &output) {
417 auto type = value.getType();
418 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
419 for (
size_t i = 0, e = bundleType.getNumElements(); i < e; ++i) {
420 auto field = getSubfield(value, i);
421 explode(field, output);
425 output.push_back(value);
428 SmallVector<Value> Visitor::explode(Value value) {
429 auto output = SmallVector<Value>();
430 explode(value, output);
435 std::pair<SmallVector<Value>,
bool> Visitor::fixOperand(Value value) {
436 auto type = value.getType();
440 if (type_isa<RefType>(type))
441 return fixRefOperand(value);
443 SmallVector<SubfieldOp> bundleAccesses;
444 SmallVector<Operation *> vectorAccesses;
450 Operation *op = value.getDefiningOp();
453 if (
auto subfieldOp = dyn_cast<SubfieldOp>(op)) {
454 value = subfieldOp.getInput();
455 bundleAccesses.push_back(subfieldOp);
458 if (
auto subindexOp = dyn_cast<SubindexOp>(op)) {
459 value = subindexOp.getInput();
460 vectorAccesses.push_back(subindexOp);
463 if (
auto subaccessOp = dyn_cast<SubaccessOp>(op)) {
464 value = subaccessOp.getInput();
465 vectorAccesses.push_back(subaccessOp);
473 value = valueMap[value];
474 assert(value &&
"canonical storage location must have been converted");
478 for (
auto subfieldOp : llvm::reverse(bundleAccesses))
479 value = getSubfield(value, subfieldOp.getFieldIndex());
484 SmallVector<Value> values;
485 bool exploded =
false;
487 if (type_isa<BundleType>(value.getType()) && !vectorAccesses.empty()) {
488 explode(value, values);
491 values.push_back(value);
496 for (
auto &value : values) {
497 for (
auto *op : llvm::reverse(vectorAccesses)) {
498 if (
auto subindexOp = dyn_cast<SubindexOp>(op)) {
499 value = getSubindex(value, subindexOp.getIndex());
502 if (
auto subaccessOp = dyn_cast<SubaccessOp>(op)) {
503 auto index = fixROperand(subaccessOp.getIndex());
504 value = getSubaccess(subaccessOp, value, index);
510 return {values, exploded};
518 Value Visitor::fixROperand(Value operand) {
519 auto [values, exploded] = fixOperand(operand);
521 return values.front();
525 ImplicitLocOpBuilder builder(operand.getLoc(), context);
526 builder.setInsertionPointAfterValue(operand);
527 return emitBundleCreate(builder, newType, values);
534 LogicalResult Visitor::visitUnhandledOp(Operation *op) {
535 ImplicitLocOpBuilder builder(op->getLoc(), op);
536 bool changed =
false;
541 SmallVector<Value> newOperands;
542 for (
auto oldOperand : op->getOperands()) {
543 auto newOperand = fixROperand(oldOperand);
544 changed |= (oldOperand != newOperand);
545 newOperands.push_back(newOperand);
550 SmallVector<Type> newTypes;
551 for (
auto oldResult : op->getResults()) {
552 auto oldType = oldResult.getType();
554 changed |= oldType != newType;
555 newTypes.push_back(newType);
559 auto *newOp = builder.clone(*op);
560 newOp->setOperands(newOperands);
561 for (
size_t i = 0, e = op->getNumResults(); i < e; ++i) {
562 auto newResult = newOp->getResult(i);
563 newResult.setType(newTypes[i]);
564 valueMap[op->getResult(i)] = newResult;
568 if (
auto portAnnos = op->getAttrOfType<ArrayAttr>(
"portAnnotations")) {
571 SmallVector<Attribute> newPortAnnos;
572 for (
unsigned i = 0, e = portAnnos.size(); i < e; ++i) {
573 auto oldType = op->getResult(i).getType();
574 auto newType = newTypes[i];
575 newPortAnnos.push_back(
576 fixAnnotations(oldType, newType, cast<ArrayAttr>(portAnnos[i])));
578 newOp->setAttr(
"portAnnotations",
ArrayAttr::get(context, newPortAnnos));
579 }
else if (newOp->getNumResults() == 1) {
584 if (
auto annos = newOp->getAttrOfType<ArrayAttr>(
"annotations")) {
585 auto oldType = op->getResult(0).getType();
586 auto newType = newTypes[0];
587 auto newAnnos = fixAnnotations(oldType, newType, annos);
592 toDelete.push_back(op);
598 for (
auto result : op->getResults())
599 valueMap[result] = result;
602 for (
auto ®ion : op->getRegions())
603 for (
auto &block : region.getBlocks())
604 for (
auto &op : block)
605 if (failed(dispatchVisitor(&op)))
615 template <
typename Op>
616 void Visitor::emitExplodedConnect(ImplicitLocOpBuilder &builder, Type type,
617 ArrayRef<Value> lhs, ArrayRef<Value> rhs) {
618 assert(lhs.size() == rhs.size() &&
619 "Something went wrong exploding the elements");
620 const auto *lhsIt = lhs.begin();
621 const auto *rhsIt = rhs.begin();
623 auto explodeConnect = [&](
auto self, Type type,
bool flip =
false) ->
void {
624 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
625 for (
auto &element : bundleType) {
626 self(
self, element.type,
flip ^ element.isFlip);
634 builder.create<Op>(lhs, rhs);
636 explodeConnect(explodeConnect, type);
639 Value Visitor::emitBundleCreate(ImplicitLocOpBuilder &builder, Type type,
640 ArrayRef<Value> values) {
641 auto *it = values.begin();
642 auto convert = [&](
auto self, Type type) -> Value {
643 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
644 SmallVector<Value> fields;
645 for (
auto element : bundleType.getElements()) {
646 fields.push_back(
self(
self, element.type));
648 return builder.create<BundleCreateOp>(type, fields);
652 return convert(convert, type);
655 template <
typename Op>
656 void Visitor::handleConnect(Op op) {
657 ImplicitLocOpBuilder builder(op.getLoc(), op);
658 auto oldLhs = op.getDest();
659 auto oldRhs = op.getSrc();
661 auto oldType = type_cast<FIRRTLType>(oldLhs.getType());
664 auto [lhs, lhsExploded] = fixOperand(oldLhs);
665 auto [rhs, rhsExploded] = fixOperand(oldRhs);
667 if (!lhsExploded && !rhsExploded && oldLhs == lhs[0] && oldRhs == rhs[0])
672 emitExplodedConnect<Op>(builder, type, lhs, rhs);
674 emitExplodedConnect<Op>(builder, type, lhs, explode(rhs[0]));
678 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
679 baseType && baseType.isPassive()) {
680 builder.create<Op>(lhs[0], emitBundleCreate(builder, type, rhs));
682 emitExplodedConnect<Op>(builder, type, explode(lhs[0]), rhs);
685 builder.create<Op>(lhs[0], rhs[0]);
689 toDelete.push_back(op);
692 LogicalResult Visitor::visitStmt(ConnectOp op) {
697 LogicalResult Visitor::visitStmt(MatchingConnectOp op) {
706 Attribute Visitor::convertBundleInVectorConstant(BundleType type,
707 ArrayRef<Attribute> fields) {
708 auto numBundleFields = type.getNumElements();
709 SmallVector<SmallVector<Attribute>> newBundleFields;
710 newBundleFields.resize(numBundleFields);
711 for (
auto bundle : fields) {
712 auto subfields = cast<ArrayAttr>(bundle);
713 for (
size_t i = 0; i < numBundleFields; ++i) {
714 newBundleFields[i].push_back(subfields[i]);
718 SmallVector<Attribute> newFieldAttrs;
719 for (
auto &newBundleField : newBundleFields) {
726 Attribute Visitor::convertVectorConstant(FVectorType oldType,
727 ArrayAttr oldElements) {
728 auto oldElementType = oldType.getElementType();
731 if (oldElementType == newElementType)
732 if (
auto bundleElementType = type_dyn_cast<BundleType>(oldElementType))
733 return convertBundleInVectorConstant(bundleElementType,
734 oldElements.getValue());
736 SmallVector<Attribute> newElements;
737 for (
auto oldElement : oldElements) {
738 newElements.push_back(convertConstant(oldElementType, oldElement));
741 auto bundleType = type_cast<BundleType>(newElementType);
742 return convertBundleInVectorConstant(bundleType, newElements);
746 Attribute Visitor::convertBundleConstant(BundleType type, ArrayAttr fields) {
747 SmallVector<Attribute> converted;
748 auto elements = type.getElements();
749 for (
size_t i = 0, e = elements.size(); i < e; ++i) {
750 converted.push_back(convertConstant(elements[i].type, fields[i]));
756 Attribute Visitor::convertConstant(Type type, Attribute value) {
757 if (
auto bundleType = type_dyn_cast<BundleType>(type))
758 return convertBundleConstant(bundleType, cast<ArrayAttr>(value));
760 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
761 return convertVectorConstant(vectorType, cast<ArrayAttr>(value));
766 LogicalResult Visitor::visitExpr(AggregateConstantOp op) {
767 auto oldValue = op.getResult();
769 auto oldType = oldValue.getType();
771 if (oldType == newType) {
772 valueMap[oldValue] = oldValue;
776 auto fields = cast<ArrayAttr>(convertConstant(oldType, op.getFields()));
778 OpBuilder builder(op);
780 builder.create<AggregateConstantOp>(op.getLoc(), newType, fields);
782 valueMap[oldValue] = newOp.getResult();
783 toDelete.push_back(op);
793 Value Visitor::sinkVecDimIntoOperands(ImplicitLocOpBuilder &builder,
795 const SmallVectorImpl<Value> &values) {
796 auto length = values.size();
797 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
798 SmallVector<Value> newFields;
799 SmallVector<BundleType::BundleElement> newElements;
800 for (
auto [i, elt] : llvm::enumerate(bundleType)) {
801 SmallVector<Value> subValues;
802 for (
auto v : values)
803 subValues.push_back(getSubfield(v, i));
804 auto newField = sinkVecDimIntoOperands(builder, elt.type, subValues);
805 newFields.push_back(newField);
806 newElements.emplace_back(elt.name,
false,
807 type_cast<FIRRTLBaseType>(newField.getType()));
810 auto newBundle = builder.create<BundleCreateOp>(newType, newFields);
814 return builder.create<VectorCreateOp>(newType, values);
817 LogicalResult Visitor::visitExpr(VectorCreateOp op) {
818 ImplicitLocOpBuilder builder(op.getLoc(), op);
820 auto oldType = op.getType();
823 if (oldType == newType) {
824 auto changed =
false;
825 SmallVector<Value> newFields;
826 for (
auto oldField : op.getFields()) {
827 auto newField = fixROperand(oldField);
828 if (oldField != newField)
830 newFields.push_back(newField);
834 auto result = op.getResult();
835 valueMap[result] = result;
840 builder.create<VectorCreateOp>(op.getLoc(), newType, newFields);
841 valueMap[op.getResult()] = newOp.getResult();
842 toDelete.push_back(op);
847 SmallVector<Value> convertedOldFields;
848 for (
auto oldField : op.getFields()) {
849 auto convertedField = fixROperand(oldField);
850 convertedOldFields.push_back(convertedField);
853 auto value = sinkVecDimIntoOperands(
854 builder,
convertType(oldType.base().getElementType()),
856 valueMap[op.getResult()] = value;
857 toDelete.push_back(op);
865 LogicalResult Visitor::visitExpr(SubfieldOp op) {
866 toDelete.push_back(op);
870 LogicalResult Visitor::visitExpr(SubindexOp op) {
871 toDelete.push_back(op);
875 LogicalResult Visitor::visitExpr(SubaccessOp op) {
876 toDelete.push_back(op);
880 LogicalResult Visitor::visitExpr(RefSubOp op) {
881 toDelete.push_back(op);
889 LogicalResult Visitor::visitExpr(RefResolveOp op) {
890 ImplicitLocOpBuilder builder(op.getLoc(), op);
891 auto [refs, exploded] = fixRefOperand(op.getRef());
894 if (ref == op.getRef()) {
895 valueMap[op.getResult()] = op.getResult();
898 auto value = builder.create<RefResolveOp>(
convertType(op.getType()), ref)
900 valueMap[op.getResult()] = value;
901 toDelete.push_back(op);
906 SmallVector<Value> values;
907 for (
auto ref : refs) {
908 values.push_back(builder
909 .create<RefResolveOp>(
910 type_cast<RefType>(ref.getType()).getType(), ref)
913 auto value = emitBundleCreate(builder, type, values);
914 valueMap[op.getResult()] = value;
915 toDelete.push_back(op);
923 LogicalResult Visitor::visit(FModuleOp op) {
924 BitVector portsToErase(op.getNumPorts() * 2);
926 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
927 auto ports = op.getPorts();
929 for (
auto [index, port] : llvm::enumerate(ports)) {
930 auto oldType = port.type;
932 if (newType == oldType)
935 newPort.type = newType;
937 fixAnnotations(oldType, newType, port.annotations.getArrayAttr()));
938 portsToErase[count + index] =
true;
939 newPorts.push_back({index + 1, newPort});
943 op.insertPorts(newPorts);
946 auto *body = op.getBodyBlock();
947 for (
unsigned i = 0, e = body->getNumArguments(); i < e; ++i) {
948 if (portsToErase[i]) {
949 auto oldArg = body->getArgument(i);
950 auto newArg = body->getArgument(i + 1);
951 valueMap[oldArg] = newArg;
953 auto oldArg = body->getArgument(i);
954 valueMap[oldArg] = oldArg;
958 for (
auto &op : *body) {
959 if (failed(dispatchVisitor(&op)))
963 while (!toDelete.empty())
964 toDelete.pop_back_val()->erase();
965 op.erasePorts(portsToErase);
975 class VBToBVPass :
public circt::firrtl::impl::VBToBVBase<VBToBVPass> {
976 void runOnOperation()
override;
980 void VBToBVPass::runOnOperation() {
981 std::vector<FModuleOp> modules;
982 llvm::append_range(modules, getOperation().getBody().getOps<FModuleOp>());
984 failableParallelForEach(&getContext(), modules, [&](FModuleOp module) {
985 Visitor visitor(&getContext());
986 return visitor.visit(module);
994 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.