diff --git a/include/circt-c/Dialect/MSFT.h b/include/circt-c/Dialect/MSFT.h index 898ce8003c..3791a7a95a 100644 --- a/include/circt-c/Dialect/MSFT.h +++ b/include/circt-c/Dialect/MSFT.h @@ -24,6 +24,9 @@ MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(MSFT, msft); MLIR_CAPI_EXPORTED void mlirMSFTRegisterPasses(); +// Values represented in `MSFT.td`. +typedef uint32_t CirctMSFTPrimitiveType; + /// Emits tcl for the specified module using the provided callback and user /// data MLIR_CAPI_EXPORTED MlirLogicalResult mlirMSFTExportTcl(MlirOperation, @@ -70,6 +73,9 @@ circtMSFTPlacementDBAddPlacement(CirctMSFTPlacementDB, MlirAttribute loc, bool circtMSFTPlacementDBTryGetInstanceAt(CirctMSFTPlacementDB, MlirAttribute loc, CirctMSFTPlacedInstance *out); +MlirAttribute circtMSFTPlacementDBGetNearestFreeInColumn( + CirctMSFTPlacementDB, CirctMSFTPrimitiveType prim, uint64_t column, + uint64_t nearestToY); //===----------------------------------------------------------------------===// // MSFT Attributes. @@ -82,9 +88,6 @@ MLIR_CAPI_EXPORTED void mlirMSFTAddPhysLocationAttr(MlirOperation op, PrimitiveType type, long x, long y, long num); -// Values represented in `MSFT.td`. -typedef uint32_t CirctMSFTPrimitiveType; - bool circtMSFTAttributeIsAPhysLocationAttribute(MlirAttribute); MlirAttribute circtMSFTPhysLocationAttrGet(MlirContext, CirctMSFTPrimitiveType, uint64_t x, uint64_t y, diff --git a/include/circt/Dialect/MSFT/PlacementDB.h b/include/circt/Dialect/MSFT/PlacementDB.h index ff5cdea807..ce6cf11acc 100644 --- a/include/circt/Dialect/MSFT/PlacementDB.h +++ b/include/circt/Dialect/MSFT/PlacementDB.h @@ -60,9 +60,19 @@ public: /// Lookup the instance at a particular location. Optional getInstanceAt(PhysLocationAttr); + /// Find the nearest unoccupied primitive location to 'nearestToY' in + /// 'column'. + PhysLocationAttr getNearestFreeInColumn(PrimitiveType prim, uint64_t column, + uint64_t nearestToY); + /// Walk the placement information in some sort of reasonable order. void walkPlacements(function_ref); + /// Walk the column placements in some sort of reasonable order. + void + walkColumnPlacements(uint64_t column, + function_ref); + private: MLIRContext *ctxt; Operation *top; diff --git a/integration_test/Bindings/Python/dialects/msft.py b/integration_test/Bindings/Python/dialects/msft.py index a6530e288d..caf361ddf0 100644 --- a/integration_test/Bindings/Python/dialects/msft.py +++ b/integration_test/Bindings/Python/dialects/msft.py @@ -94,12 +94,20 @@ with ir.Context() as ctx, ir.Location.unknown(): devdb = msft.DeviceDB() assert not devdb.is_valid_location(physAttr) devdb.add_primitive(physAttr) + devdb.add_primitive(msft.PhysLocationAttr.get(msft.M20K, x=2, y=50, num=1)) assert devdb.is_valid_location(physAttr) seeded_pdb = msft.PlacementDB(top.operation, devdb) + + print(seeded_pdb.get_nearest_free_in_column(msft.M20K, 2, 4)) + # CHECK: #msft.physloc + rc = seeded_pdb.add_placement(physAttr, path, "subpath", resolved_inst) assert rc + print(seeded_pdb.get_nearest_free_in_column(msft.M20K, 2, 4)) + # CHECK: #msft.physloc + bad_loc = msft.PhysLocationAttr.get(msft.M20K, x=7, y=99, num=1) rc = seeded_pdb.add_placement(bad_loc, path, "subpath", resolved_inst) assert not rc diff --git a/lib/Bindings/Python/MSFTModule.cpp b/lib/Bindings/Python/MSFTModule.cpp index 373f3cf903..eaad6e49f5 100644 --- a/lib/Bindings/Python/MSFTModule.cpp +++ b/lib/Bindings/Python/MSFTModule.cpp @@ -63,6 +63,14 @@ public: std::string subpath(inst.subpath, inst.subpathLength); return (py::tuple)py::cast(std::make_tuple(inst.path, subpath, inst.op)); } + py::object getNearestFreeInColumn(CirctMSFTPrimitiveType prim, + uint64_t column, uint64_t nearestToY) { + MlirAttribute nearest = circtMSFTPlacementDBGetNearestFreeInColumn( + db, prim, column, nearestToY); + if (!nearest.ptr) + return py::none(); + return py::cast(nearest); + } private: CirctMSFTPlacementDB db; @@ -179,6 +187,9 @@ void circt::python::populateDialectMSFTSubmodule(py::module &m) { .def("add_placement", &PlacementDB::addPlacement, "Inform the DB about a new placement.", py::arg("location"), py::arg("path"), py::arg("subpath"), py::arg("op")) + .def("get_nearest_free_in_column", &PlacementDB::getNearestFreeInColumn, + "Find the nearest free primitive location in column.", + py::arg("prim_type"), py::arg("column"), py::arg("nearest_to_y")) .def("get_instance_at", &PlacementDB::getInstanceAt, "Get the instance at location. Returns None if nothing exists " "there. Otherwise, returns (path, subpath, op) of the instance " diff --git a/lib/CAPI/Dialect/MSFT.cpp b/lib/CAPI/Dialect/MSFT.cpp index 8aacf4a27c..7c5c89e80e 100644 --- a/lib/CAPI/Dialect/MSFT.cpp +++ b/lib/CAPI/Dialect/MSFT.cpp @@ -102,6 +102,14 @@ bool circtMSFTPlacementDBTryGetInstanceAt(CirctMSFTPlacementDB self, return true; } +MlirAttribute circtMSFTPlacementDBGetNearestFreeInColumn( + CirctMSFTPlacementDB cdb, CirctMSFTPrimitiveType prim, uint64_t column, + uint64_t nearestToY) { + auto db = unwrap(cdb); + return wrap( + db->getNearestFreeInColumn((PrimitiveType)prim, column, nearestToY)); +} + //===----------------------------------------------------------------------===// // MSFT Attributes. //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/MSFT/PlacementDB.cpp b/lib/Dialect/MSFT/PlacementDB.cpp index 633979a4db..87d7daef25 100644 --- a/lib/Dialect/MSFT/PlacementDB.cpp +++ b/lib/Dialect/MSFT/PlacementDB.cpp @@ -112,6 +112,27 @@ PlacementDB::getInstanceAt(PhysLocationAttr loc) { return instF->getSecond(); } +PhysLocationAttr PlacementDB::getNearestFreeInColumn(PrimitiveType prim, + uint64_t columnNum, + uint64_t nearestToY) { + // Simplest possible algorithm. + PhysLocationAttr nearest = {}; + walkColumnPlacements(columnNum, [&nearest, columnNum](PhysLocationAttr loc, + PlacedInstance inst) { + if (inst.op) + return; + if (!nearest) { + nearest = loc; + return; + } + int64_t curDist = std::abs((int64_t)columnNum - (int64_t)nearest.getY()); + int64_t replDist = std::abs((int64_t)columnNum - (int64_t)loc.getY()); + if (replDist < curDist) + nearest = loc; + }); + return nearest; +} + Optional PlacementDB::getLeaf(PhysLocationAttr loc) { PrimitiveType primType = loc.getPrimitiveType().getValue(); @@ -119,11 +140,10 @@ PlacementDB::getLeaf(PhysLocationAttr loc) { DimNumMap &nums = placements[loc.getX()][loc.getY()]; if (!seeded) return &nums[loc.getNum()][primType]; - - auto primitivesF = nums.find(loc.getNum()); - if (primitivesF == nums.end()) + if (!nums.count(loc.getNum())) return {}; - auto primitives = primitivesF->second; + + DimDevType &primitives = nums[loc.getNum()]; if (primitives.count(primType) == 0) return {}; return &primitives[primType]; @@ -136,30 +156,41 @@ void PlacementDB::walkPlacements( for (auto colF = placements.begin(), colE = placements.end(); colF != colE; ++colF) { size_t x = colF->getFirst(); - DimYMap yMap = colF->getSecond(); + walkColumnPlacements(x, callback); + } +} - // Y loop. - for (auto rowF = yMap.begin(), rowE = yMap.end(); rowF != rowE; ++rowF) { - size_t y = rowF->getFirst(); - DimNumMap numMap = rowF->getSecond(); +/// Walk the column placements in some sort of reasonable order. +void PlacementDB::walkColumnPlacements( + uint64_t columnNum, + function_ref callback) { - // Num loop. - for (auto numF = numMap.begin(), numE = numMap.end(); numF != numE; - ++numF) { - size_t num = numF->getFirst(); - DimDevType devMap = numF->getSecond(); + auto colF = placements.find(columnNum); + if (colF == placements.end()) + return; + DimYMap yMap = colF->getSecond(); - // DevType loop. - for (auto devF = devMap.begin(), devE = devMap.end(); devF != devE; - ++devF) { - PrimitiveType devtype = devF->getFirst(); - PlacedInstance inst = devF->getSecond(); + // Y loop. + for (auto rowF = yMap.begin(), rowE = yMap.end(); rowF != rowE; ++rowF) { + size_t y = rowF->getFirst(); + DimNumMap numMap = rowF->getSecond(); - // Marshall and run the callback. - PhysLocationAttr loc = PhysLocationAttr::get( - ctxt, PrimitiveTypeAttr::get(ctxt, devtype), x, y, num); - callback(loc, inst); - } + // Num loop. + for (auto numF = numMap.begin(), numE = numMap.end(); numF != numE; + ++numF) { + size_t num = numF->getFirst(); + DimDevType devMap = numF->getSecond(); + + // DevType loop. + for (auto devF = devMap.begin(), devE = devMap.end(); devF != devE; + ++devF) { + PrimitiveType devtype = devF->getFirst(); + PlacedInstance inst = devF->getSecond(); + + // Marshall and run the callback. + PhysLocationAttr loc = PhysLocationAttr::get( + ctxt, PrimitiveTypeAttr::get(ctxt, devtype), columnNum, y, num); + callback(loc, inst); } } }