ODB: replace struct UnfoldedModel with dbObject-backed unfolded model #10588
ODB: replace struct UnfoldedModel with dbObject-backed unfolded model #10588osamahammad21 wants to merge 5 commits into
Conversation
Signed-off-by: osamahammad21 <osama@precisioninno.com>
…ructuree Signed-off-by: osamahammad21 <osama@precisioninno.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the unfolded model representation in ODB by replacing the non-persistent UnfoldedModel with persistent dbObject-derived classes (dbUnfoldedChip, dbUnfoldedRegion, dbUnfoldedBump, dbUnfoldedConn, and dbUnfoldedNet) and introducing a dbUnfoldedBuilder. The review feedback highlights several critical issues, including a missing table instantiation in one of the dbDatabase constructors, multiple potential null pointer dereferences due to a lack of defensive checks on lookups, and style violations where helper lambdas should be refactored into free functions in anonymous namespaces.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| chip_net_itr_ = new dbChipNetItr(chip_net_tbl_); | ||
|
|
||
| unfolded_model_ = nullptr; | ||
| unfolded_region_itr_ = new dbUnfoldedRegionItr(unfolded_region_tbl_); |
There was a problem hiding this comment.
The second constructor _dbDatabase::_dbDatabase(_dbDatabase* db, int id) is missing the instantiation of the new unfolded_*_tbl_ tables (e.g., unfolded_chip_tbl_, unfolded_region_tbl_, etc.). Since unfolded_region_itr_ and unfolded_bump_itr_ are initialized using these tables, this will lead to a null pointer dereference or undefined behavior when they are accessed. Please instantiate these tables in this constructor as well, similar to the first constructor.
unfolded_chip_tbl_ = new dbTable<_dbUnfoldedChip>(this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbUnfoldedChipObj);
unfolded_region_tbl_ = new dbTable<_dbUnfoldedRegion>(this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbUnfoldedRegionObj);
unfolded_bump_tbl_ = new dbTable<_dbUnfoldedBump>(this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbUnfoldedBumpObj);
unfolded_conn_tbl_ = new dbTable<_dbUnfoldedConn>(this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbUnfoldedConnObj);
unfolded_net_tbl_ = new dbTable<_dbUnfoldedNet>(this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbUnfoldedNetObj);
unfolded_region_itr_ = new dbUnfoldedRegionItr(unfolded_region_tbl_);| dbChipBump* bump = bump_inst->getChipBump(); | ||
| if (bump->getInst() == nullptr) { |
There was a problem hiding this comment.
| { | ||
| auto& chip_region_map = region_map_[uf_chip->getOID()]; | ||
| for (auto* region_inst : inst->getRegions()) { | ||
| auto region = region_inst->getChipRegion(); |
| dbChipBumpInst* bump_inst | ||
| = (dbChipBumpInst*) db->chip_bump_inst_tbl_->getPtr(obj->chip_bump_inst_); | ||
| dbInst* inst = bump_inst->getChipBump()->getInst(); | ||
| if (inst == nullptr) { | ||
| return Point3D(); | ||
| } | ||
| Point pt = inst->getBBox()->getBox().center(); | ||
| dbUnfoldedRegion* region | ||
| = (dbUnfoldedRegion*) db->unfolded_region_tbl_->getPtr( | ||
| obj->parent_region_); | ||
| _dbUnfoldedRegion* _region = (_dbUnfoldedRegion*) region; | ||
| _dbUnfoldedChip* parent_chip | ||
| = db->unfolded_chip_tbl_->getPtr(_region->parent_chip_); | ||
| parent_chip->transform_.apply(pt); | ||
| return Point3D(pt.x(), pt.y(), region->getSurfaceZ()); |
There was a problem hiding this comment.
This method lacks defensive null checks for bump_inst, bump_inst->getChipBump(), region, and parent_chip. If any of these lookups return nullptr, it will result in a crash. Please add appropriate null checks.
dbChipBumpInst* bump_inst
= (dbChipBumpInst*) db->chip_bump_inst_tbl_->getPtr(obj->chip_bump_inst_);
if (bump_inst == nullptr) {
return Point3D();
}
dbChipBump* bump = bump_inst->getChipBump();
if (bump == nullptr) {
return Point3D();
}
dbInst* inst = bump->getInst();
if (inst == nullptr) {
return Point3D();
}
Point pt = inst->getBBox()->getBox().center();
dbUnfoldedRegion* region
= (dbUnfoldedRegion*) db->unfolded_region_tbl_->getPtr(
obj->parent_region_);
if (region == nullptr) {
return Point3D();
}
_dbUnfoldedRegion* _region = (_dbUnfoldedRegion*) region;
_dbUnfoldedChip* parent_chip
= db->unfolded_chip_tbl_->getPtr(_region->parent_chip_);
if (parent_chip != nullptr) {
parent_chip->transform_.apply(pt);
}
return Point3D(pt.x(), pt.y(), region->getSurfaceZ());| dbChipRegionInst* reg_inst | ||
| = (dbChipRegionInst*) db->chip_region_inst_tbl_->getPtr( | ||
| obj->chip_region_inst_); | ||
| Cuboid c = reg_inst->getChipRegion()->getCuboid(); | ||
| _dbUnfoldedChip* parent = db->unfolded_chip_tbl_->getPtr(obj->parent_chip_); | ||
| parent->transform_.apply(c); |
There was a problem hiding this comment.
Please add defensive null checks for reg_inst, reg_inst->getChipRegion(), and parent to prevent potential null pointer dereferences.
dbChipRegionInst* reg_inst
= (dbChipRegionInst*) db->chip_region_inst_tbl_->getPtr(
obj->chip_region_inst_);
if (reg_inst == nullptr) {
return Cuboid();
}
dbChipRegion* region = reg_inst->getChipRegion();
if (region == nullptr) {
return Cuboid();
}
Cuboid c = region->getCuboid();
_dbUnfoldedChip* parent = db->unfolded_chip_tbl_->getPtr(obj->parent_chip_);
if (parent != nullptr) {
parent->transform_.apply(c);
}| auto describe = [](dbUnfoldedRegion* r, dbMarker* marker) { | ||
| const Cuboid cuboid = r->getCuboid(); | ||
| marker->addSource(r->getChipRegionInst()); | ||
| marker->addShape( | ||
| Rect(cuboid.xMin(), cuboid.yMin(), cuboid.xMax(), cuboid.yMax())); | ||
| return fmt::format("{}/{} (faces {})", | ||
| r->parent_chip->name, | ||
| r->region_inst->getChipRegion()->getName(), | ||
| sideToString(r->effective_side)); | ||
| r->getParentChip()->getName(), | ||
| r->getChipRegionInst()->getChipRegion()->getName(), | ||
| sideToString(r->getEffectiveSide())); | ||
| }; |
There was a problem hiding this comment.
Helper logic should be defined as a free function in a namespace rather than as a local lambda within a function. Please refactor the describe lambda into a free function in an anonymous namespace, and add defensive null checks for r, r->getParentChip(), and r->getChipRegionInst() to prevent potential null pointer dereferences.
namespace {
std::string describe(dbUnfoldedRegion* r, dbMarker* marker) {
if (r == nullptr) {
return "NULL";
}
const Cuboid cuboid = r->getCuboid();
marker->addSource(r->getChipRegionInst());
marker->addShape(
Rect(cuboid.xMin(), cuboid.yMin(), cuboid.xMax(), cuboid.yMax()));
dbUnfoldedChip* parent = r->getParentChip();
std::string chip_name = parent ? parent->getName() : "UNKNOWN";
dbChipRegionInst* region_inst = r->getChipRegionInst();
std::string region_name = (region_inst && region_inst->getChipRegion())
? region_inst->getChipRegion()->getName()
: "UNKNOWN";
return fmt::format("{}/{} (faces {})",
chip_name,
region_name,
sideToString(r->getEffectiveSide()));
}
} // namespaceReferences
- Helper logic should be defined as a free function in a namespace rather than as a local lambda within a function.
| auto get_net_name = [&](dbUnfoldedBump* bump) -> std::string { | ||
| auto it = bump_net_map.find(bump); | ||
| if (it != bump_net_map.end()) { | ||
| return it->second->chip_net->getName(); | ||
| return it->second->getChipNet()->getName(); | ||
| } | ||
| return "defines no net"; | ||
| }; |
There was a problem hiding this comment.
Helper logic should be defined as a free function in a namespace rather than as a local lambda within a function. Please refactor the get_net_name lambda into a free function in an anonymous namespace, passing the map as a parameter, and add a null check for the returned chip net.
namespace {
std::string get_net_name(dbUnfoldedBump* bump, const std::map<dbUnfoldedBump*, dbUnfoldedNet*>& bump_net_map) {
auto it = bump_net_map.find(bump);
if (it != bump_net_map.end() && it->second != nullptr) {
dbChipNet* chip_net = it->second->getChipNet();
if (chip_net != nullptr) {
return chip_net->getName();
}
}
return "defines no net";
}
} // namespaceReferences
- Helper logic should be defined as a free function in a namespace rather than as a local lambda within a function.
| if (path.empty()) { | ||
| continue; | ||
| } | ||
| dbBlock* block = path.back()->getMasterChip()->getBlock(); |
There was a problem hiding this comment.
Please add defensive null checks for path.back() and path.back()->getMasterChip() to prevent potential null pointer dereferences.
| dbBlock* block = path.back()->getMasterChip()->getBlock(); | |
| dbChipInst* leaf = path.back(); | |
| if (leaf == nullptr) { | |
| continue; | |
| } | |
| dbChip* master_chip = leaf->getMasterChip(); | |
| if (master_chip == nullptr) { | |
| continue; | |
| } | |
| dbBlock* block = master_chip->getBlock(); |
| if (conn->getTopRegion() && conn->getBottomRegion()) { | ||
| auto it1 = chip_map.find(conn->getTopRegion()->getParentChip()); | ||
| auto it2 = chip_map.find(conn->getBottomRegion()->getParentChip()); | ||
| if (it1 != chip_map.end() && it2 != chip_map.end()) { | ||
| uf.unite(it1->second, it2->second); | ||
| } |
There was a problem hiding this comment.
To improve robustness, please check that getParentChip() does not return nullptr before performing the map lookup.
if (conn->getTopRegion() && conn->getBottomRegion()) {
dbUnfoldedChip* top_chip = conn->getTopRegion()->getParentChip();
dbUnfoldedChip* bot_chip = conn->getBottomRegion()->getParentChip();
if (top_chip != nullptr && bot_chip != nullptr) {
auto it1 = chip_map.find(top_chip);
auto it2 = chip_map.find(bot_chip);
if (it1 != chip_map.end() && it2 != chip_map.end()) {
uf.unite(it1->second, it2->second);
}
}
}| for (const auto& id : obj->chip_inst_path_) { | ||
| path.push_back((dbChipInst*) db->chip_inst_tbl_->getPtr(id)); | ||
| } |
There was a problem hiding this comment.
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Signed-off-by: osamahammad21 <osama@precisioninno.com>
| "name": "effective_side_", | ||
| "type": "uint32_t", | ||
| "default": 0, | ||
| "flags": ["private"] |
There was a problem hiding this comment.
There are only four values. Why not use a "bits": 2 ?
| if (master->getChipType() == dbChip::ChipType::HIER) { | ||
| for (auto* sub : master->getChipInsts()) { |
There was a problem hiding this comment.
No unfolding of HIER chips implies you are flattening rather than unfolding.
| void dbUnfoldedBuilder::unfoldNets(dbChip* chip, | ||
| const std::vector<dbChipInst*>& parent_path) | ||
| { | ||
| for (auto* net : chip->getChipNets()) { | ||
| _dbUnfoldedNet* uf_net = db_->unfolded_net_tbl_->create(); |
There was a problem hiding this comment.
How does this work in the presence of hiearchy? It seems like you would get hierarhical nets
|
Have you resolved the gemini comments? |
|
Rename classes as discussed to better align unfolded names to the object they are unfolding. |
Summary
Replaces the struct-based
UnfoldedModelwith a persistent dbObject-backed unfolded model that lives underdbDatabase. Adds five newdbObjectclasses —dbUnfoldedChip,dbUnfoldedRegion,dbUnfoldedBump,dbUnfoldedConn,dbUnfoldedNet— populated bydbUnfoldedBuilder(which walks the chip-instance tree the same way the old constructor did). Geometry that the struct model stored (chip/region cuboids, bump global positions) is now computed on demand from sourcedbInsttransforms instead of cached. The 3DBlox checker is migrated to the new API;unfoldedModel.{h,cpp}and the oldgetUnfoldedModel()accessor are removed.Type of Change
Impact
dbDatabase::constructUnfoldedModel()is preserved as the build entry point; it now populates the new dbObject tables instead of the old struct.isUsedbit is no longer stored —checkInternalExtUsagederives the same set from a single pass overgetUnfoldedConns().bump_inst_map/region_mapindices (the largest cost in 3DBlox-scale designs); region cuboids and bump global positions are computed, not stored. The dbObject tables themselves are flaggedno-serialfor now (no.odbsize change).dbUnfoldedInst, alignment markers can fold into that._dbDatabasedeserialization (multi-chip designs) is unchanged.Verification
./etc/Build.sh).Related Issues
N/A