Skip to content

FastIntDiv: fallback to normal division when values exceed 32-bit ran… - #3093

Open
huuanhhuyn wants to merge 4 commits into
NVIDIA:mainfrom
huuanhhuyn:fastintdiv_64
Open

FastIntDiv: fallback to normal division when values exceed 32-bit ran…#3093
huuanhhuyn wants to merge 4 commits into
NVIDIA:mainfrom
huuanhhuyn:fastintdiv_64

Conversation

@huuanhhuyn

@huuanhhuyn huuanhhuyn commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

FastIntDiv: Fallback during runtime to the normal division when division values exceed 32-bit range.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

FastIntDiv now supports mixed integer operand types, fallback arithmetic for unsupported ranges, expanded correctness tests, and CUDA benchmarks comparing fast and native division/modulo for 32-bit and 64-bit integers.

FastIntDiv behavior and validation

Layer / File(s) Summary
Native division and modulo fallbacks
cpp/include/raft/util/fast_int_div.cuh
Adds fallback state propagation, mixed-type / and % operators, and canonical arithmetic for unsupported ranges.
Arithmetic and construction tests
cpp/tests/util/fast_int_div.cu
Tests invalid denominators and compares same-type and cross-type division/modulo results with native arithmetic.
CUDA benchmark coverage
cpp/bench/prims/util/fast_int_div.cu, cpp/bench/prims/CMakeLists.txt
Adds fast/native int32 and int64 benchmarks and registers the new benchmark source in the utility suite.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly reflects the main change: FastIntDiv now falls back to native division outside the 32-bit range.
Description check ✅ Passed The description is directly about the same FastIntDiv runtime fallback behavior described by the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/include/raft/util/fast_int_div.cuh`:
- Around line 102-105: Update the range guards in both fast integer division and
modulo operators to reject any operand above INT32_MAX, not merely values with
nonzero bits 63:32, and fall back to native division/modulo for all
overflow-risk inputs. Preserve the existing fast path only when both operands
are within the supported signed 32-bit range, and add regression vectors
covering UINT32_MAX, divisors above INT32_MAX, and matching native
quotient/remainder results.

In `@cpp/tests/util/fast_int_div.cu`:
- Around line 25-39: Update the numerator coverage in
CompareWithNativeDivisionInt32 and the corresponding int64 test to include
INT32_MIN and INT64_MIN explicitly. Preserve the existing magnitude/sign
combinations and divisor coverage while adding these signed minimum boundary
values directly to the tested numerator vectors.
- Around line 41-54: Extend the magnitudes and/or divisors in
CompareWithNativeDivisionInt64 with values immediately beyond the signed 32-bit
boundary, including INT32_MAX + 2 and UINT32_MAX. Keep the existing
signed-positive and negative numerator coverage, and ensure both operator/ and
operator% remain compared against native division and remainder.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 15ea5333-6f28-4096-bea3-68f7254928d7

📥 Commits

Reviewing files that changed from the base of the PR and between aa9a6d5 and aeeeab0.

📒 Files selected for processing (2)
  • cpp/include/raft/util/fast_int_div.cuh
  • cpp/tests/util/fast_int_div.cu

Comment thread cpp/include/raft/util/fast_int_div.cuh Outdated
Comment thread cpp/tests/util/fast_int_div.cu Outdated
Comment thread cpp/tests/util/fast_int_div.cu Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
cpp/include/raft/util/fast_int_div.cuh (3)

74-90: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Initialize scalar members on the fallback path.

A directly constructed unsupported int64_t divisor returns before assigning m and p. The copy constructor then reads those indeterminate members, even though later operations use the fallback path.

Proposed fix
-  UIntT m;
+  UIntT m{};
...
-  int p;
+  int p{};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/raft/util/fast_int_div.cuh` around lines 74 - 90, Initialize the
scalar members m and p before the unsupported-divisor early return in
computeScalars, ensuring directly constructed int64_t divisors leave both
members in a defined state while fallback remains enabled. Preserve the existing
handling for valid, zero, and negative divisors.

78-90: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Clear stale fallback state before recomputing scalars.

After assigning a supported divisor to an instance that previously held an unsupported one, fallback remains true and permanently bypasses the fast path. Reset it at the start of computeScalars() and add a fallback-to-supported assignment regression test.

Proposed fix
 void computeScalars()
 {
+  fallback = false;
   if (d == 1) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/raft/util/fast_int_div.cuh` around lines 78 - 90, Reset fallback
to false at the beginning of computeScalars() before evaluating the divisor, so
recomputation after changing from an unsupported divisor can re-enable the fast
path. Add a regression test that assigns an unsupported divisor, then a
supported divisor, and verifies fast-path scalar computation is used.

111-136: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Constrain the new overloads to integral numerators.

These templates now accept floating-point numerators. For example, 5.5f / FastIntDiv<int32_t>{2} selects this overload, truncates 5.5f to 5, and returns 2.0f rather than 2.75f. Restrict both overloads to integral NumIntT.

Proposed fix
-template <typename NumIntT, typename DivIntT>
+template <typename NumIntT,
+          typename DivIntT,
+          std::enable_if_t<std::is_integral_v<NumIntT>, int> = 0>
 HDI std::common_type_t<NumIntT, DivIntT> operator/(NumIntT n, const FastIntDiv<DivIntT>& divisor)

-template <typename NumIntT, typename DivIntT>
+template <typename NumIntT,
+          typename DivIntT,
+          std::enable_if_t<std::is_integral_v<NumIntT>, int> = 0>
 HDI std::common_type_t<NumIntT, DivIntT> operator%(NumIntT n, const FastIntDiv<DivIntT>& divisor)

As per path instructions, cpp/REVIEW_GUIDELINES.md requires public operator template signature changes to be reviewed for downstream impact.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/raft/util/fast_int_div.cuh` around lines 111 - 136, Restrict the
public operator/ and operator% templates for FastIntDiv to integral NumIntT
types using the project’s existing constraint or enablement convention. Preserve
the current integer behavior and return types for supported numerators, while
preventing floating-point numerators such as float from selecting either
overload.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/include/raft/util/fast_int_div.cuh`:
- Around line 18-19: Add a direct <limits> include to the header containing
kInt32Min and kInt32Max so std::numeric_limits is explicitly declared without
relying on transitive includes.

---

Outside diff comments:
In `@cpp/include/raft/util/fast_int_div.cuh`:
- Around line 74-90: Initialize the scalar members m and p before the
unsupported-divisor early return in computeScalars, ensuring directly
constructed int64_t divisors leave both members in a defined state while
fallback remains enabled. Preserve the existing handling for valid, zero, and
negative divisors.
- Around line 78-90: Reset fallback to false at the beginning of
computeScalars() before evaluating the divisor, so recomputation after changing
from an unsupported divisor can re-enable the fast path. Add a regression test
that assigns an unsupported divisor, then a supported divisor, and verifies
fast-path scalar computation is used.
- Around line 111-136: Restrict the public operator/ and operator% templates for
FastIntDiv to integral NumIntT types using the project’s existing constraint or
enablement convention. Preserve the current integer behavior and return types
for supported numerators, while preventing floating-point numerators such as
float from selecting either overload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8dd452d7-1ae4-444d-a60a-1ad44733eaa1

📥 Commits

Reviewing files that changed from the base of the PR and between aeeeab0 and 22845bb.

📒 Files selected for processing (2)
  • cpp/include/raft/util/fast_int_div.cuh
  • cpp/tests/util/fast_int_div.cu

Comment thread cpp/include/raft/util/fast_int_div.cuh
@huuanhhuyn
huuanhhuyn requested a review from a team as a code owner July 27, 2026 14:20

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cpp/bench/prims/util/fast_int_div.cu (1)

100-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use typed RAFT mdarrays for these buffers.

These are simple one-dimensional owning arrays, but two use rmm::device_uvector and d_divisors uses an untyped byte buffer plus a cast. Replace them with typed RAFT mdarrays to remove byte-size/cast bookkeeping and follow the project storage idiom.

As per coding guidelines, “Prefer raft mdarray types for owning data over rmm::device_uvector, rmm::device_buffer, or std::vector when an mdarray fits the use case.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/bench/prims/util/fast_int_div.cu` around lines 100 - 102, Replace the
owning buffers d_numerators, d_divisors, and out_d with one-dimensional typed
RAFT mdarrays using their appropriate element types and existing
resource/context. Update their construction and accesses to use mdarray storage
directly, removing the untyped byte-size bookkeeping and casts while preserving
the current data flow.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/bench/prims/util/fast_int_div.cu`:
- Around line 57-70: Update the benchmark data generation around the numerator
and divisor distributions to add separately named int64 fallback cases using
values above the int32 range, including divisors outside the 32-bit range.
Preserve the existing int32-ranged cases, and ensure the new cases are passed to
FastIntDiv<int64_t> so they exercise the actual fallback paths.

---

Nitpick comments:
In `@cpp/bench/prims/util/fast_int_div.cu`:
- Around line 100-102: Replace the owning buffers d_numerators, d_divisors, and
out_d with one-dimensional typed RAFT mdarrays using their appropriate element
types and existing resource/context. Update their construction and accesses to
use mdarray storage directly, removing the untyped byte-size bookkeeping and
casts while preserving the current data flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 57e24140-6188-4986-94fb-db80b918f127

📥 Commits

Reviewing files that changed from the base of the PR and between 22845bb and b974d8b.

📒 Files selected for processing (3)
  • cpp/bench/prims/CMakeLists.txt
  • cpp/bench/prims/util/fast_int_div.cu
  • cpp/include/raft/util/fast_int_div.cuh
🚧 Files skipped from review as they are similar to previous changes (1)
  • cpp/include/raft/util/fast_int_div.cuh

Comment thread cpp/bench/prims/util/fast_int_div.cu Outdated
* an `IntT` numerator.
*/
template <typename IntT, typename DivisorT>
RAFT_KERNEL divmod_kernel(const IntT* numerators,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

TODO: bench in-place gather() and scatter() runtime before and after the overflow bug fix

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.

1 participant