[CTS] Fix cloned ICG location collision in mapLocationToSink_#9864
[CTS] Fix cloned ICG location collision in mapLocationToSink_#9864openroad-ci wants to merge 4 commits intoThe-OpenROAD-Project:masterfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request addresses a bug where multiple ICG clones placed at the same location would cause an entry in mapLocationToSink_ to be overwritten, effectively disconnecting one of the ICGs. The fix introduces a collision resolution mechanism that tracks occupied positions and shifts new clones to a unique location if a collision is detected. The changes look good and are supported by a new regression test. I have a couple of suggestions: one to improve performance by avoiding redundant work, and another to prevent a potential infinite loop in the collision resolution logic.
src/cts/src/TritonCTS.cpp
Outdated
| int shift = 1; | ||
| if (!block_->getRows().empty()) { | ||
| shift = block_->getRows().begin()->getSite()->getWidth(); | ||
| } |
There was a problem hiding this comment.
There's a potential for an infinite loop here. If block_->getRows() is not empty but block_->getRows().begin()->getSite()->getWidth() returns 0, shift will be set to 0. If a location collision occurs, the while loop on line 1205 will never terminate because cloneLoc will not be updated.
To make this more robust, you should ensure shift is always a positive value.
int shift = 1;
if (!block_->getRows().empty()) {
const int site_width = block_->getRows().begin()->getSite()->getWidth();
if (site_width > 0) {
shift = site_width;
}
}There was a problem hiding this comment.
Resolved by removing the use of getWidth().
src/cts/src/TritonCTS.cpp
Outdated
| void TritonCTS::cloneClockGaters(odb::dbNet* clkNet) | ||
| { | ||
| // Seed with all existing instance positions to prevent clones from | ||
| // landing on a pre-existing cell and causing mapLocationToSink_ | ||
| // key collision in HTreeBuilder. | ||
| std::set<odb::Point> occupiedPositions; | ||
| for (odb::dbInst* inst : block_->getInsts()) { | ||
| int x, y; | ||
| inst->getLocation(x, y); | ||
| occupiedPositions.emplace(x, y); | ||
| } | ||
| cloneClockGaters(clkNet, occupiedPositions); | ||
| } |
There was a problem hiding this comment.
This function iterates over all instances in the block to populate occupiedPositions. Since cloneClockGaters is called for each clock net within populateTritonCTS, this can lead to significant performance degradation on designs with many clock nets and instances, as the instance list is traversed repeatedly.
To optimize this, I recommend creating the occupiedPositions set once in populateTritonCTS before the clock net loop and passing it to the overloaded cloneClockGaters function. This would make the population of existing instance locations a one-time operation.
References
- When analyzing code within a loop, consider the entire loop structure. Operations at the beginning of the loop can affect the logic within the loop body, potentially making similar calls inside the loop redundant.
|
clang-tidy review says "All clean, LGTM! 👍" |
1 similar comment
|
clang-tidy review says "All clean, LGTM! 👍" |
|
Fixes #9816 Failure Sequence
// Connected clone (correct)
AND2_X1 \clone_11_..._11727_
(.A1(\..._WORD_ITER[2].CG_Inst.clk_en ),
.A2(\clknet_leaf_164_..._06692_ ),
.ZN(\..._WORD_ITER[2].CG_Inst.clk_o ));
// Disconnected clone (BUG)
AND2_X1 \clone_10_..._11727_
(.A1(\..._WORD_ITER[2].CG_Inst.clk_en ),
.ZN(\..._WORD_ITER[2].CG_Inst.clk_o ));
// NOTE: .A2 missing — clock input is floatingRoot Cause
Later, This manifests as missing clock connections on ICG clock input pins in designs with symmetrically placed gated clock sinks (e.g., Solution
|
When cloneClockGaters() places multiple ICG clones at the same sinksBbox center, the single-valued mapLocationToSink_ map in HTreeBuilder silently overwrites earlier entries, disconnecting ICGs from the clock tree. Add resolveLocationCollision() to ensure each clone gets a unique position by tracking all occupied instance positions and shifting colliding clones by site width. Physical overlap is resolved by the subsequent detailed_placement step in the ORFS flow. Add colocated_sinks regression test that reproduces the bug with two ICGs whose sink bounding boxes share the same center. Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Avoid re-iterating all block instances per clock net by seeding the occupiedPositions set once in populateTritonCTS() before the clock net loop, instead of inside the per-net wrapper. Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
4c1ab98 to
6be2024
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
|
@arthurjolo I found cloned ICG cell location collision, which is similar to the previous issue #9313 . |
|
@arthurjolo I found this during the debugging. [ Current: Allow cell overlaps during CTS + DPL ]
[ Proposed: Just-in-time legalization when a new cell is inserted during CTS ]
|
Summary
cloneClockGaters()places multiple ICG clones at the samesinksBboxcenter, the single-valuedmapLocationToSink_map in HTreeBuilder silently overwrites earlier entries, disconnecting ICGs from the clock tree.resolveLocationCollision()to ensure each clone gets a unique position by tracking all occupied instance positions and shifting colliding clones by site width.detailed_placementstep in the ORFS flow.Test plan
colocated_sinksregression test that reproduces the bug with two ICGs whose sink bounding boxes share the same center