Skip to content

Constant-fold unsigned division/remainder in bv_utils#9025

Open
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:bvutils-constant-fold-div
Open

Constant-fold unsigned division/remainder in bv_utils#9025
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:bvutils-constant-fold-div

Conversation

@tautschnig

Copy link
Copy Markdown
Collaborator

bv_utilst::unsigned_divider always allocated fresh variables for the quotient and remainder, with a quotientdivisor + rem == dividend multiplier constraint, even when both operands are constant. The result was therefore never a constant literal, so a constant division feeding a later multiply produced a (hard) variablevariable multiplier instead of folding away.

Add a fast path: when both operands are constant (and the divisor is non-zero), compute the quotient and remainder directly as constants. Division by zero falls through to the existing nondeterministic encoding, so semantics are unchanged.

  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@tautschnig tautschnig self-assigned this Jun 3, 2026
Copilot AI review requested due to automatic review settings June 3, 2026 07:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a constant-folding fast path to bv_utilst::unsigned_divider so that divisions/remainders of two constant bitvectors produce constant bitvector literals (instead of introducing fresh SAT variables plus a q*d + r == n multiplier constraint), improving downstream simplification and avoiding hard variable×variable multipliers when constant divisions feed later arithmetic.

Changes:

  • Add a fast path in bv_utilst::unsigned_divider to directly compute quotient/remainder when both operands are constant and divisor is non-zero.
  • Add unit tests ensuring constant folding occurs for 100/7, and that division-by-zero still uses the existing nondeterministic encoding.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/solvers/flattening/bv_utils.cpp Implements constant-folding fast path for unsigned division/remainder on constant operands.
unit/solvers/flattening/bv_utils.cpp Adds regression tests for constant folding and division-by-zero non-folding behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/solvers/flattening/bv_utils.cpp
Comment thread unit/solvers/flattening/bv_utils.cpp
@codecov

codecov Bot commented Jun 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.60%. Comparing base (5453820) to head (5edac12).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #9025      +/-   ##
===========================================
- Coverage    80.60%   80.60%   -0.01%     
===========================================
  Files         1711     1712       +1     
  Lines       189466   189538      +72     
  Branches        73       73              
===========================================
+ Hits        152719   152776      +57     
- Misses       36747    36762      +15     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tautschnig tautschnig force-pushed the bvutils-constant-fold-div branch from 7198d09 to 90c9c1f Compare June 9, 2026 08:06
bv_utilst::unsigned_divider always allocated fresh variables for the
quotient and remainder, with a quotient*divisor + rem == dividend
multiplier constraint, even when both operands are constant.  The result
was therefore never a constant literal, so a constant division feeding a
later multiply produced a (hard) variable*variable multiplier instead of
folding away.

Add a fast path: when both operands are constant (and the divisor is
non-zero), compute the quotient and remainder directly as constants.
Division by zero falls through to the existing nondeterministic encoding,
so semantics are unchanged.  The constant-bv reconstruction goes through
binary2integer to mirror build_constant's use of integer2binary.

Make the long-standing equal-width assumption shared by the rest of
unsigned_divider (unsigned_multiplier_no_overflow / equal(sum, op0))
explicit by asserting op0.size() == op1.size() at the top of the
function; this also rules out an out-of-bounds read in the new fast
path.

Unit-test coverage in unit/solvers/flattening/bv_utils.cpp pins:
- 100 / 7 folds to constant 14 rem 2;
- exact division 100 / 5 folds to 20 rem 0;
- divide-by-one folds to numerator rem 0;
- a non-constant divisor bypasses the fast path (guarding the
  is_constant(op0) && is_constant(op1) conjunction);
- divide-by-zero keeps fresh variables for both quotient and remainder.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
@tautschnig tautschnig force-pushed the bvutils-constant-fold-div branch from 90c9c1f to 5edac12 Compare June 9, 2026 08:13
@tautschnig tautschnig assigned kroening and unassigned tautschnig Jun 10, 2026
// Reconstruct each operand into mp_integer via binary2integer, mirroring
// the inverse used by build_constant (which calls integer2binary).
std::string s0(width, '0'), s1(width, '0');
for(std::size_t i = 0; i < width; i++)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to add bv_utilst::from_constant or the like.

@kroening kroening assigned tautschnig and unassigned kroening Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants