231 bool emitWireAtBlockBegin =
false) {
232 Block *block = op.getBlock();
233 auto builder = ImplicitLocOpBuilder::atBlockBegin(op.getLoc(), block);
234 bool isProceduralRegion = op.getParentOp()->hasTrait<ProceduralRegion>();
236 auto createWireForResult = [&](Value result, StringAttr name) {
238 Type wireElementType = result.getType();
239 bool isResultInOut =
false;
242 if (
auto inoutType = hw::type_dyn_cast<hw::InOutType>(result.getType())) {
243 wireElementType = inoutType.getElementType();
244 isResultInOut =
true;
248 if (isProceduralRegion)
249 newWire = builder.create<LogicOp>(wireElementType, name);
251 newWire = builder.create<
sv::WireOp>(wireElementType, name);
254 while (!result.use_empty()) {
255 OpOperand &use = *result.getUses().begin();
260 use.set(newWireRead);
261 newWireRead->moveBefore(use.getOwner());
272 if (isProceduralRegion)
273 connect = builder.create<BPAssignOp>(
274 newWire, isResultInOut ? resultRead.getResult() : result);
277 newWire, isResultInOut ? resultRead.getResult() : result);
279 connect->moveAfter(&op);
281 resultRead->moveBefore(connect);
284 if (!emitWireAtBlockBegin) {
290 newWire.getDefiningOp()->moveAfter(&op);
296 if (op.getNumResults() == 1) {
298 op.removeAttr(
"sv.namehint");
299 createWireForResult(op.getResult(0), namehint);
304 for (
auto result : op.getResults())
305 createWireForResult(result, StringAttr());
847 ArrayRef<WireLowering> wireLowerings) {
848 bool isProceduralRegion = block.getParentOp()->hasTrait<ProceduralRegion>();
850 for (
auto [hwWireOp, declarePoint, assignPoint] : wireLowerings) {
852 ImplicitLocOpBuilder builder(hwWireOp.getLoc(), &block, declarePoint);
854 if (isProceduralRegion) {
855 decl = builder.create<LogicOp>(hwWireOp.getType(), hwWireOp.getNameAttr(),
856 hwWireOp.getInnerSymAttr());
859 builder.create<
sv::WireOp>(hwWireOp.getType(), hwWireOp.getNameAttr(),
860 hwWireOp.getInnerSymAttr());
864 auto defaultAttrNames = hwWireOp.getAttributeNames();
865 for (
auto namedAttr : hwWireOp->getAttrs())
866 if (!llvm::is_contained(defaultAttrNames, namedAttr.getName()))
867 decl.getDefiningOp()->setAttr(namedAttr.getName(),
868 namedAttr.getValue());
873 if (assignPoint != declarePoint)
874 builder.setInsertionPoint(&block, assignPoint);
875 if (isProceduralRegion)
876 builder.
create<BPAssignOp>(decl, hwWireOp.getInput());
878 builder.create<
AssignOp>(decl, hwWireOp.getInput());
884 if (assignPoint != declarePoint)
885 builder.setInsertionPointAfterValue(decl);
889 hwWireOp.replaceAllUsesWith(readOp.getResult());
892 for (
auto [hwWireOp, declarePoint, assignPoint] : wireLowerings)
903 for (
auto &op : block) {
905 for (
auto ®ion : op.getRegions()) {
916 SmallVector<WireLowering> wireLowerings;
924 bool isProceduralRegion = block.getParentOp()->hasTrait<ProceduralRegion>();
928 DenseSet<Operation *> visitedAlwaysInlineOperations;
932 SmallVector<Operation *> debugOpsToMoveToEnd;
934 for (Block::iterator opIterator = block.begin(), e = block.end();
936 auto &op = *opIterator++;
938 if (!isa<CombDialect, SVDialect, HWDialect, ltl::LTLDialect,
939 verif::VerifDialect, debug::DebugDialect>(op.getDialect())) {
940 auto d = op.emitError() <<
"dialect \"" << op.getDialect()->getNamespace()
941 <<
"\" not supported for direct Verilog emission";
942 d.attachNote() <<
"ExportVerilog cannot emit this operation; it needs "
943 "to be lowered before running ExportVerilog";
948 if (isa<ltl::LTLDialect>(op.getDialect()))
952 if (isa<debug::DebugDialect>(op.getDialect())) {
953 debugOpsToMoveToEnd.push_back(&op);
962 if (
auto inst = dyn_cast<HWInstanceLike>(op)) {
971 if (
auto call = dyn_cast<mlir::CallOpInterface>(op))
976 if (isProceduralRegion && isa<LogicOp, RegOp>(op)) {
981 op.moveBefore(parentOp);
988 isProceduralRegion) {
994 if (!mlir::isMemoryEffectFree(&op)) {
1014 if (op.use_empty()) {
1020 if (visitedAlwaysInlineOperations.insert(&op).second)
1026 if (
auto aggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op);
1028 if (hw::StructType structType =
1029 type_dyn_cast<hw::StructType>(aggregateConstantOp.getType())) {
1031 SmallVector<Value> operands;
1032 ImplicitLocOpBuilder builder(op.getLoc(), op.getContext());
1033 builder.setInsertionPointAfter(&op);
1034 for (
auto [value, field] :
1035 llvm::zip(aggregateConstantOp.getFieldsAttr(),
1036 structType.getElements())) {
1037 if (
auto arrayAttr = dyn_cast<mlir::ArrayAttr>(value))
1039 builder.create<hw::AggregateConstantOp>(field.type, arrayAttr));
1042 field.type, cast<mlir::IntegerAttr>(value)));
1047 aggregateConstantOp.getResult().replaceAllUsesWith(structCreate);
1049 opIterator = std::next(op.getIterator());
1056 if (
auto structCreateOp = dyn_cast<hw::StructCreateOp>(op);
1061 ImplicitLocOpBuilder builder(op.getLoc(), &op);
1062 hw::StructType structType =
1063 cast<hw::StructType>(structCreateOp.getResult().getType());
1064 bool procedural = op.getParentOp()->hasTrait<ProceduralRegion>();
1066 wireOp = builder.create<LogicOp>(structType);
1068 wireOp = builder.create<
sv::WireOp>(structType);
1070 for (
auto [input, field] :
1071 llvm::zip(structCreateOp.getInput(), structType.getElements())) {
1073 builder.
create<sv::StructFieldInOutOp>(wireOp, field.name);
1075 builder.create<BPAssignOp>(target, input);
1077 builder.create<
AssignOp>(target, input);
1081 llvm::make_early_inc_range(structCreateOp.getResult().getUses()))
1084 structCreateOp.erase();
1092 IndexedPartSelectInOutOp, IndexedPartSelectOp>(&op)) {
1097 if (
auto maybeReadOp =
1099 if (isa_and_nonnull<sv::WireOp, LogicOp>(
1100 maybeReadOp.getInput().getDefiningOp())) {
1101 wireOp = maybeReadOp.getInput();
1102 readOp = maybeReadOp;
1107 ImplicitLocOpBuilder builder(op.getLoc(), &op);
1109 auto type = op.getOperand(1).getType();
1110 const auto *name =
"_GEN_ARRAY_IDX";
1111 if (op.getParentOp()->hasTrait<ProceduralRegion>()) {
1112 wireOp = builder.create<LogicOp>(type, name);
1113 builder.create<BPAssignOp>(wireOp, op.getOperand(1));
1115 wireOp = builder.create<
sv::WireOp>(type, name);
1120 op.setOperand(1, readOp);
1123 sv::addSVAttributes(wireOp.getDefiningOp(),
1124 SVAttributeAttr::get(wireOp.getContext(),
"keep",
1138 if (!isProceduralRegion ||
1142 if (!op.getParentOp()->hasTrait<ProceduralRegion>())
1149 if (isProceduralRegion)
1166 if (op.getNumOperands() > 2 && op.getNumResults() == 1 &&
1167 op.hasTrait<mlir::OpTrait::IsCommutative>() &&
1168 mlir::isMemoryEffectFree(&op) && op.getNumRegions() == 0 &&
1169 op.getNumSuccessors() == 0 &&
1170 llvm::all_of(op.getAttrs(), [](NamedAttribute attr) {
1171 return attr.getNameDialect() != nullptr ||
1172 attr.getName() ==
"twoState";
1175 SmallVector<Operation *> newOps;
1177 op.getResult(0).replaceAllUsesWith(result);
1181 opIterator = Block::iterator(newOps.front());
1186 if (
auto addOp = dyn_cast<comb::AddOp>(op)) {
1187 if (
auto cst = addOp.getOperand(1).getDefiningOp<
hw::ConstantOp>()) {
1188 assert(addOp.getNumOperands() == 2 &&
"commutative lowering is done");
1189 if (cst.getValue().isNegative()) {
1191 opIterator = Block::iterator(firstOp);
1199 if (
auto structExplodeOp = dyn_cast<hw::StructExplodeOp>(op)) {
1201 opIterator = Block::iterator(firstOp);
1213 auto debugBuilder = OpBuilder::atBlockEnd(&block);
1214 if (!block.empty() && block.back().mightHaveTrait<OpTrait::IsTerminator>())
1215 debugBuilder.setInsertionPoint(&block.back());
1216 for (
auto *op : debugOpsToMoveToEnd) {
1218 debugBuilder.insert(op);
1221 if (isProceduralRegion) {
1230 std::pair<Block *, Block::iterator> logicOpInsertionPoint =
1232 for (
auto &op : llvm::make_early_inc_range(block)) {
1233 if (
auto logic = dyn_cast<LogicOp>(&op)) {
1236 if (logicOpInsertionPoint.second == logic->getIterator()) {
1237 ++logicOpInsertionPoint.second;
1241 logic->moveBefore(logicOpInsertionPoint.first,
1242 logicOpInsertionPoint.second);
1252 SmallPtrSet<Operation *, 32> seenOperations;
1254 for (
auto &op : llvm::make_early_inc_range(block)) {
1257 if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
1263 bool haveAnyOutOfOrderUses =
false;
1264 for (
auto *userOp : op.getUsers()) {
1267 while (&block != &userOp->getParentRegion()->front())
1268 userOp = userOp->getParentOp();
1270 if (seenOperations.count(userOp)) {
1271 haveAnyOutOfOrderUses =
true;
1277 seenOperations.insert(&op);
1280 if (!haveAnyOutOfOrderUses)
1286 op.moveBefore(&block.front());
1292 op.moveBefore(&block.front());
1298 if (
auto readInOut = dyn_cast<ReadInOutOp>(op)) {
1299 auto *def = readInOut.getInput().getDefiningOp();
1301 op.moveBefore(&block.front());
1302 def->moveBefore(&block.front());