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"
37using namespace firrtl;
46 explicit Visitor(MLIRContext *);
48 LogicalResult visit(FModuleOp);
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;
138Visitor::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)));
159 return BundleType::get(context, elements);
161 for (
auto size :
llvm::reverse(dimensions))
162 type = FVectorType::
get(type, size);
167 auto cached = typeMap.lookup(type);
169 return type_cast<FIRRTLBaseType>(cached);
171 SmallVector<unsigned> dimensions;
174 typeMap.insert({type, converted});
178RefType Visitor::convertType(RefType type) {
179 auto cached = typeMap.lookup(type);
181 return type_cast<RefType>(cached);
182 auto converted = RefType::get(
convertType(type.getType()),
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))
199Type Visitor::convertType(Type type) {
200 if (
auto firrtlType = type_dyn_cast<FIRRTLType>(type))
210void 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);
224void 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);
270 auto i64Type = IntegerType::get(context, 64);
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);
277 anno.setMember(
"circt.fieldID", IntegerAttr::get(i64Type, fieldID));
278 newAnnos.push_back(anno.getAttr());
282ArrayAttr 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);
286 return ArrayAttr::get(context, newAnnos);
293Value 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);
304Value 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);
315Value 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);
324Value 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);
339void 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);
353std::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};
416void 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);
428SmallVector<Value> Visitor::explode(Value value) {
429 auto output = SmallVector<Value>();
430 explode(value, output);
435std::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};
518Value 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);
534LogicalResult 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)))
615template <
typename Op>
616void 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);
639Value 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);
655template <
typename Op>
656void 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);
692LogicalResult Visitor::visitStmt(ConnectOp op) {
697LogicalResult Visitor::visitStmt(MatchingConnectOp op) {
706Attribute 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) {
720 newFieldAttrs.push_back(ArrayAttr::get(context, newBundleField));
722 return ArrayAttr::get(context, newFieldAttrs);
726Attribute 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);
746Attribute 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]));
752 return ArrayAttr::get(context, converted);
756Attribute 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));
766LogicalResult 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);
793Value 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()));
809 auto newType = BundleType::get(builder.getContext(), newElements);
810 auto newBundle = builder.create<BundleCreateOp>(newType, newFields);
813 auto newType = FVectorType::get(type, length);
814 return builder.create<VectorCreateOp>(newType, values);
817LogicalResult 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);
865LogicalResult Visitor::visitExpr(SubfieldOp op) {
866 toDelete.push_back(op);
870LogicalResult Visitor::visitExpr(SubindexOp op) {
871 toDelete.push_back(op);
875LogicalResult Visitor::visitExpr(SubaccessOp op) {
876 toDelete.push_back(op);
880LogicalResult Visitor::visitExpr(RefSubOp op) {
881 toDelete.push_back(op);
889LogicalResult 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);
923LogicalResult 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);
975class VBToBVPass :
public circt::firrtl::impl::VBToBVBase<VBToBVPass> {
976 void runOnOperation()
override;
980void 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.
ResultType visitInvalidOp(Operation *op, ExtraArgs... args)
visitInvalidOp is an override point for non-FIRRTL dialect operations.
ResultType visitUnhandledOp(Operation *op, ExtraArgs... args)
visitUnhandledOp is an override point for FIRRTL dialect ops that the concrete visitor didn't bother ...
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createVBToBVPass()
ModulePort::Direction flip(ModulePort::Direction direction)
Flip a port direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.