rsz: Fix global sizing overflow cases#10658
Conversation
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Eren Dogan <erendogan@google.com> Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a Lagrangian-Relaxation-driven global sizing and Vt assignment optimization phase (GLOBAL_SIZING) to the Resizer. It adds the LRSubproblem class to evaluate per-gate costs in a worker-safe parallel manner, and the GlobalSizingPolicy class to manage the outer optimization loop. The review feedback highlights critical issues regarding the handling of invalid timing path delays (-sta::INF), which could corrupt cost calculations and slack budgets. Additionally, the reviewer identified subtle out-of-bounds bugs where std::cmp_greater_equal and std::cmp_less fail to protect against negative signed indices, recommending safer static_cast<size_t> checks instead.
| const float d = sta::delayAsFloat(resizer_->gateDelay( | ||
| cand_port, o.load_cap, scene, max_, arc_delay_calc)); | ||
| cost += timing_weight * o.lambda_sum * d; |
There was a problem hiding this comment.
If resizer_->gateDelay returns -sta::INF (indicating no valid timing path exists for the candidate cell), sta::delayAsFloat will return a very large negative value. This will incorrectly decrease the cost, making the invalid candidate highly favored. We should check if the delay is invalid (e.g., d < -1e9f) and return std::numeric_limits<float>::infinity() to reject the candidate.
const float d = sta::delayAsFloat(resizer_->gateDelay(
cand_port, o.load_cap, scene, max_, arc_delay_calc));
if (d < -1e9f) {
return std::numeric_limits<float>::infinity();
}
cost += timing_weight * o.lambda_sum * d;| const float d_U = sta::delayAsFloat(resizer_->gateDelay( | ||
| u.drv_port, load_pert, scene, max_, arc_delay_calc)); | ||
| cost += timing_weight * u.lambda_U_drv * d_U; |
There was a problem hiding this comment.
Similarly, if the upstream gate delay d_U is invalid (-sta::INF), it will incorrectly decrease the cost. We should check if d_U < -1e9f and return infinity.
const float d_U = sta::delayAsFloat(resizer_->gateDelay(
u.drv_port, load_pert, scene, max_, arc_delay_calc));
if (d_U < -1e9f) {
return std::numeric_limits<float>::infinity();
}
cost += timing_weight * u.lambda_U_drv * d_U;| const float d_cur = sta::delayAsFloat( | ||
| resizer_->gateDelay(o.port, o.load_cap, scene, max_, arc_delay_calc)); | ||
| const float d_cand = sta::delayAsFloat(resizer_->gateDelay( | ||
| cand_port, o.load_cap, scene, max_, arc_delay_calc)); | ||
| if (d_cand - d_cur > budget) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
If d_cand or d_cur is invalid (-sta::INF), the budget check d_cand - d_cur > budget can produce incorrect results (e.g., -infinity > budget is false, incorrectly allowing the downsize). We should return false if either delay is invalid.
const float d_cur = sta::delayAsFloat(
resizer_->gateDelay(o.port, o.load_cap, scene, max_, arc_delay_calc));
const float d_cand = sta::delayAsFloat(resizer_->gateDelay(
cand_port, o.load_cap, scene, max_, arc_delay_calc));
if (d_cand < -1e9f || d_cur < -1e9f) {
return false;
}
if (d_cand - d_cur > budget) {
return false;
}| const float d = sta::delayAsFloat( | ||
| resizer_.gateDelay(port, load, scene, policy_max_)); | ||
| gate_t += lam_sum * d; | ||
| has_pressure = true; |
There was a problem hiding this comment.
If resizer_.gateDelay returns -sta::INF, d will be extremely negative, which can corrupt the median timing calculation in computeAutoTimingWeight. We should skip adding the delay to gate_t if it is invalid.
| const float d = sta::delayAsFloat( | |
| resizer_.gateDelay(port, load, scene, policy_max_)); | |
| gate_t += lam_sum * d; | |
| has_pressure = true; | |
| const float d = sta::delayAsFloat( | |
| resizer_.gateDelay(port, load, scene, policy_max_)); | |
| if (d > -1e9f) { | |
| gate_t += lam_sum * d; | |
| has_pressure = true; | |
| } |
| const sta::EdgeId id = graph_->id(e); | ||
| if (std::cmp_greater_equal(id, lambda_size)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Using std::cmp_greater_equal(id, lambda_size) does not protect against out-of-bounds access if id is negative, because a negative signed integer compared to a positive lambda_size will return false, leading to an out-of-bounds access on lambda[id]. Using static_cast<size_t>(id) >= static_cast<size_t>(lambda_size) is safer and more consistent with the rest of the codebase.
| const sta::EdgeId id = graph_->id(e); | |
| if (std::cmp_greater_equal(id, lambda_size)) { | |
| continue; | |
| } | |
| const sta::EdgeId id = graph_->id(e); | |
| if (static_cast<size_t>(id) >= static_cast<size_t>(lambda_size)) { | |
| continue; | |
| } |
| const sta::VertexId vid = graph_->id(v); | ||
| const float vbudget = std::cmp_less(vid, budget_size) | ||
| ? budget[vid] | ||
| : std::numeric_limits<float>::max(); |
There was a problem hiding this comment.
Using std::cmp_less(vid, budget_size) can lead to out-of-bounds access on budget[vid] if vid is negative, because a negative signed integer is less than budget_size, resulting in a true condition. Using static_cast<size_t>(vid) < static_cast<size_t>(budget_size) is safer and correctly handles negative IDs by wrapping them to large unsigned values.
| const sta::VertexId vid = graph_->id(v); | |
| const float vbudget = std::cmp_less(vid, budget_size) | |
| ? budget[vid] | |
| : std::numeric_limits<float>::max(); | |
| const sta::VertexId vid = graph_->id(v); | |
| const float vbudget = (static_cast<size_t>(vid) < static_cast<size_t>(budget_size)) | |
| ? budget[vid] | |
| : std::numeric_limits<float>::max(); |
| const sta::EdgeId id = graph_->id(e); | ||
| if (std::cmp_greater_equal(id, lambda_size)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Using std::cmp_greater_equal(id, lambda_size) does not protect against out-of-bounds access if id is negative. Using static_cast<size_t>(id) >= static_cast<size_t>(lambda_size) is safer and more consistent with the rest of the codebase.
| const sta::EdgeId id = graph_->id(e); | |
| if (std::cmp_greater_equal(id, lambda_size)) { | |
| continue; | |
| } | |
| const sta::EdgeId id = graph_->id(e); | |
| if (static_cast<size_t>(id) >= static_cast<size_t>(lambda_size)) { | |
| continue; | |
| } |
Summary
Problem
5e83a17805e9d009e46ae2c5be952f5771db43fcfrom the public OpenROAD repository.Solution
secure-explore-global-sizingOpenROAD branch through the approved private-to-public workflow.tools/OpenROAD.Impact
Testing
Reviewer Notes
5e83a17805.Related