233 bool emitWireAtBlockBegin =
false) {
234 Block *block = op.getBlock();
235 auto builder = ImplicitLocOpBuilder::atBlockBegin(op.getLoc(), block);
238 auto createWireForResult = [&](Value result, StringAttr name) {
240 Type wireElementType = result.getType();
241 bool isResultInOut =
false;
244 if (
auto inoutType = hw::type_dyn_cast<hw::InOutType>(result.getType())) {
245 wireElementType = inoutType.getElementType();
246 isResultInOut =
true;
247 }
else if (
auto handleElementType =
248 sv::getHandleElementType(result.getType())) {
249 wireElementType = handleElementType;
250 isResultInOut =
true;
254 if (isProceduralRegion)
255 newWire = LogicOp::create(builder, wireElementType, name);
260 while (!result.use_empty()) {
261 OpOperand &use = *result.getUses().begin();
266 use.set(newWireRead);
267 newWireRead->moveBefore(use.getOwner());
278 if (isProceduralRegion)
279 connect = BPAssignOp::create(
280 builder, newWire, isResultInOut ? resultRead.getResult() : result);
283 builder, newWire, isResultInOut ? resultRead.getResult() : result);
285 connect->moveAfter(&op);
287 resultRead->moveBefore(connect);
290 if (!emitWireAtBlockBegin) {
296 newWire.getDefiningOp()->moveAfter(&op);
302 if (op.getNumResults() == 1) {
304 op.removeAttr(
"sv.namehint");
305 createWireForResult(op.getResult(0), namehint);
310 for (
auto result : op.getResults())
311 createWireForResult(result, StringAttr());
866 ArrayRef<WireLowering> wireLowerings) {
867 bool isProceduralRegion = block.getParentOp()->hasTrait<
ProceduralRegion>();
869 for (
auto [hwWireOp, declarePoint, assignPoint] : wireLowerings) {
871 ImplicitLocOpBuilder builder(hwWireOp.getLoc(), &block, declarePoint);
873 if (isProceduralRegion) {
875 LogicOp::create(builder, hwWireOp.getType(), hwWireOp.getNameAttr(),
876 hwWireOp.getInnerSymAttr());
879 hwWireOp.getNameAttr(),
880 hwWireOp.getInnerSymAttr());
884 auto defaultAttrNames = hwWireOp.getAttributeNames();
885 for (
auto namedAttr : hwWireOp->getAttrs())
886 if (!llvm::is_contained(defaultAttrNames, namedAttr.getName()))
887 decl.getDefiningOp()->setAttr(namedAttr.getName(),
888 namedAttr.getValue());
893 if (assignPoint != declarePoint)
894 builder.setInsertionPoint(&block, assignPoint);
895 if (isProceduralRegion)
896 BPAssignOp::create(builder, decl, hwWireOp.getInput());
904 if (assignPoint != declarePoint)
905 builder.setInsertionPointAfterValue(decl);
909 hwWireOp.replaceAllUsesWith(readOp.getResult());
912 for (
auto [hwWireOp, declarePoint, assignPoint] : wireLowerings)
923 for (
auto &op : block) {
925 for (
auto ®ion : op.getRegions()) {
936 SmallVector<WireLowering> wireLowerings;
944 bool isProceduralRegion = block.getParentOp()->hasTrait<
ProceduralRegion>();
948 DenseSet<Operation *> visitedAlwaysInlineOperations;
952 SmallVector<Operation *> debugOpsToMoveToEnd;
954 for (Block::iterator opIterator = block.begin(), e = block.end();
956 auto &op = *opIterator++;
958 if (!isa<CombDialect, SVDialect, HWDialect, ltl::LTLDialect,
959 verif::VerifDialect, debug::DebugDialect>(op.getDialect())) {
960 auto d = op.emitError() <<
"dialect \"" << op.getDialect()->getNamespace()
961 <<
"\" not supported for direct Verilog emission";
962 d.attachNote() <<
"ExportVerilog cannot emit this operation; it needs "
963 "to be lowered before running ExportVerilog";
968 if (isa<ltl::LTLDialect>(op.getDialect()))
972 if (isa<debug::DebugDialect>(op.getDialect())) {
973 debugOpsToMoveToEnd.push_back(&op);
982 if (
auto inst = dyn_cast<HWInstanceLike>(op)) {
991 if (
auto call = dyn_cast<mlir::CallOpInterface>(op))
996 if (isProceduralRegion && isa<LogicOp, RegOp>(op)) {
1001 op.moveBefore(parentOp);
1008 isProceduralRegion) {
1014 if (!mlir::isMemoryEffectFree(&op)) {
1034 if (op.use_empty()) {
1040 if (visitedAlwaysInlineOperations.insert(&op).second)
1046 if (
auto aggregateConstantOp = dyn_cast<hw::AggregateConstantOp>(op);
1048 if (hw::StructType structType =
1051 SmallVector<Value> operands;
1052 ImplicitLocOpBuilder builder(op.getLoc(), op.getContext());
1053 builder.setInsertionPointAfter(&op);
1054 for (
auto [value, field] :
1055 llvm::zip(aggregateConstantOp.getFieldsAttr(),
1056 structType.getElements())) {
1057 if (
auto arrayAttr = dyn_cast<mlir::ArrayAttr>(value))
1058 operands.push_back(hw::AggregateConstantOp::create(
1059 builder, field.type, arrayAttr));
1062 builder, field.type, cast<mlir::IntegerAttr>(value)));
1067 aggregateConstantOp.getResult().replaceAllUsesWith(structCreate);
1069 opIterator = std::next(op.getIterator());
1076 if (
auto structCreateOp = dyn_cast<hw::StructCreateOp>(op);
1081 ImplicitLocOpBuilder builder(op.getLoc(), &op);
1082 hw::StructType structType =
1083 cast<hw::StructType>(structCreateOp.getResult().getType());
1086 wireOp = LogicOp::create(builder, structType);
1090 for (
auto [input, field] :
1091 llvm::zip(structCreateOp.getInput(), structType.getElements())) {
1093 sv::StructFieldInOutOp::create(builder, wireOp, field.name);
1095 BPAssignOp::create(builder, target, input);
1101 llvm::make_early_inc_range(structCreateOp.getResult().getUses()))
1104 structCreateOp.erase();
1110 if (
auto arrayInjectOp = dyn_cast<hw::ArrayInjectOp>(op)) {
1112 ImplicitLocOpBuilder builder(op.getLoc(), &op);
1115 decl = LogicOp::create(builder, arrayInjectOp.getType());
1117 decl = sv::RegOp::create(builder, arrayInjectOp.getType());
1118 for (
auto &use : llvm::make_early_inc_range(arrayInjectOp->getUses()))
1124 auto alwaysOp = sv::AlwaysCombOp::create(builder);
1125 builder.setInsertionPointToStart(alwaysOp.getBodyBlock());
1129 sv::BPAssignOp::create(builder, decl, arrayInjectOp.getInput());
1132 auto target = sv::ArrayIndexInOutOp::create(builder, decl,
1133 arrayInjectOp.getIndex());
1134 sv::BPAssignOp::create(builder, target, arrayInjectOp.getElement());
1136 arrayInjectOp.erase();
1144 IndexedPartSelectInOutOp, IndexedPartSelectOp>(&op)) {
1149 if (
auto maybeReadOp =
1151 if (isa_and_nonnull<sv::WireOp, LogicOp>(
1152 maybeReadOp.getInput().getDefiningOp())) {
1153 wireOp = maybeReadOp.getInput();
1154 readOp = maybeReadOp;
1159 ImplicitLocOpBuilder builder(op.getLoc(), &op);
1161 auto type = op.getOperand(1).getType();
1162 const auto *name =
"_GEN_ARRAY_IDX";
1164 wireOp = LogicOp::create(builder, type, name);
1165 BPAssignOp::create(builder, wireOp, op.getOperand(1));
1172 op.setOperand(1, readOp);
1175 sv::addSVAttributes(wireOp.getDefiningOp(),
1176 SVAttributeAttr::get(wireOp.getContext(),
"keep",
1190 if (!isProceduralRegion ||
1201 if (isProceduralRegion)
1219 if (op.getNumOperands() != 2 && op.getNumResults() == 1 &&
1220 op.hasTrait<mlir::OpTrait::IsCommutative>() &&
1221 mlir::isMemoryEffectFree(&op) && op.getNumRegions() == 0 &&
1222 op.getNumSuccessors() == 0 &&
1223 llvm::all_of(op.getAttrs(), [](NamedAttribute attr) {
1224 return attr.getNameDialect() != nullptr ||
1225 attr.getName() ==
"twoState";
1228 SmallVector<Operation *> newOps;
1230 op.getResult(0).replaceAllUsesWith(result);
1234 if (!newOps.empty())
1235 opIterator = Block::iterator(newOps.front());
1240 if (
auto addOp = dyn_cast<comb::AddOp>(op)) {
1241 if (
auto cst = addOp.getOperand(1).getDefiningOp<
hw::ConstantOp>()) {
1242 assert(addOp.getNumOperands() == 2 &&
"commutative lowering is done");
1243 if (cst.getValue().isNegative()) {
1245 opIterator = Block::iterator(firstOp);
1253 if (
auto structExplodeOp = dyn_cast<hw::StructExplodeOp>(op)) {
1255 opIterator = Block::iterator(firstOp);
1267 auto debugBuilder = OpBuilder::atBlockEnd(&block);
1268 if (!block.empty() && block.back().mightHaveTrait<OpTrait::IsTerminator>())
1269 debugBuilder.setInsertionPoint(&block.back());
1270 for (
auto *op : debugOpsToMoveToEnd) {
1272 debugBuilder.insert(op);
1275 if (isProceduralRegion) {
1284 std::pair<Block *, Block::iterator> logicOpInsertionPoint =
1286 for (
auto &op : llvm::make_early_inc_range(block)) {
1287 if (isa<LogicOp, VarOp>(op)) {
1290 if (logicOpInsertionPoint.second == op.getIterator()) {
1291 ++logicOpInsertionPoint.second;
1295 op.moveBefore(logicOpInsertionPoint.first,
1296 logicOpInsertionPoint.second);
1306 SmallPtrSet<Operation *, 32> seenOperations;
1308 for (
auto &op : llvm::make_early_inc_range(block)) {
1311 if (isa<ltl::LTLDialect, debug::DebugDialect>(op.getDialect()))
1317 bool haveAnyOutOfOrderUses =
false;
1318 for (
auto *userOp : op.getUsers()) {
1321 while (&block != &userOp->getParentRegion()->front())
1322 userOp = userOp->getParentOp();
1324 if (seenOperations.count(userOp)) {
1325 haveAnyOutOfOrderUses =
true;
1331 seenOperations.insert(&op);
1334 if (!haveAnyOutOfOrderUses)
1340 op.moveBefore(&block.front());
1346 op.moveBefore(&block.front());
1352 if (
auto readInOut = dyn_cast<ReadInOutOp>(op)) {
1353 auto *def = readInOut.getInput().getDefiningOp();
1355 op.moveBefore(&block.front());
1356 def->moveBefore(&block.front());