Skip to content

fix(cuda-oxide): lower core::intrinsics::float_to_int_unchecked - #1654

Open
veljjanoski wants to merge 1 commit into
NVIDIA:mainfrom
veljjanoski:fix/float-to-int-unchecked
Open

veljjanoski wants to merge 1 commit into
NVIDIA:mainfrom
veljjanoski:fix/float-to-int-unchecked

Conversation

@veljjanoski

Copy link
Copy Markdown

Summary

f32::to_int_unchecked and f64::to_int_unchecked call core::intrinsics::float_to_int_unchecked. The importer had no handler for that intrinsic, so a kernel using either failed with "invalid input program" (#1595). This adds it the same way #473 added exact_div, and lowers it to a plain fptosi/fptoui. The caller promises the value is finite and in range, so the clamping and NaN handling of the saturating as cast are not needed. rustc's LLVM backend emits the same instructions.

Fixes #1595.

Changes

  • dialect-mir: new CALLEE_FLOAT_TO_INT_UNCHECKED placeholder, registered as a known placeholder that never needs libdevice.
  • mir-importer: new intrinsics::float_to_int module and its terminator dispatch.
  • mir-lower: the placeholder lowers to llvm.fptosi or llvm.fptoui. Signedness comes from the MIR result type, as in the saturating cast. Other sources (f16, f128) and destinations wider than 64 bits get a clear error, matching what the saturating cast supports on both intrinsic backends.
  • Tests: importer path recognition, the placeholder round trip, and a lowering test on both intrinsic backends that checks for fptosi/fptoui and no remaining call. A second test checks that an i128 destination is rejected.
  • New example float_to_int_unchecked covering f32→i32, f32→u32, f64→i64 and f64→u64. Each kernel gets inputs that only the right instruction converts correctly: negative values for the signed kernels, values above the signed maximum for the unsigned ones. Its Cargo.lock is copied from exact_div_chunks, which has the same dependencies, so the example pins match.

Testing

Run on an RTX 3090 (sm_86), CUDA 13.3, WSL2 Ubuntu 24.04, Rust 1.99.1.

Before the change, on main (9df9e7c):

Translation failed: f64_to_i64: [".../core/src/convert/num.rs": line: 20, column: 30] Compilation error: invalid input program.
       Unsupported construct: rustc intrinsic `std::intrinsics::float_to_int_unchecked` is not yet supported on the device

After:

$ cargo oxide run float_to_int_unchecked --arch sm_86
f32 -> i32: 256 / 256 correct
f32 -> u32: 256 / 256 correct
f64 -> i64: 256 / 256 correct
f64 -> u64: 256 / 256 correct

PASS

PTX for f32_to_i32, with x[i] as i32 compared to x[i].to_int_unchecked::<i32>():

// as i32
setp.ltu.f32    %p14, %r8, 0fCF000000;
cvt.rzi.s32.f32 %r9, %r8;
selp.b32        %r10, -2147483648, %r9, %p14;
setp.gt.f32     %p15, %r8, 0f4EFFFFFF;
selp.b32        %r11, 2147483647, %r10, %p15;
setp.nan.f32    %p16, %r8, %r8;
selp.b32        %r12, 0, %r11, %p16;

// to_int_unchecked::<i32>
cvt.rzi.s32.f32 %r9, %r8;

Across the four kernels, the as version adds 10 float compares and 10 selects. The to_int_unchecked version has neither; its only selects are the 4 from the index checks, which both versions share.

  • just -f cuda-oxide/Justfile check passes (the local mirror of CI: fmt, clippy, tests, guards, docs)
  • cargo oxide run <example> passes, or cuda-oxide/scripts/smoketest.sh -o '^<example>$'
  • New example added (if applicable)

Also run: cargo clippy --locked --all-targets -- -D warnings in the example, and scripts/sync-example-locks.sh --check.

Checklist

  • All commits signed off (git commit -s)
  • SPDX headers on new source files

AI-usage disclosure: Claude (Anthropic) was used as assistant.

Signed-off-by: Daniel Veljjanoski <danielveljanoski@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 26, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

This branch has not been deployed

No deployments
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.

[BUG]: f32::to_int_unchecked fails with "invalid input program" in a kernel

1 participant