Repository navigation
Support simd_reduce_max and simd_reduce_min on integer lanes - #4934
Conversation
|
@CYJ904 @Tianshu-Huang @wodex1nhaoIeng @acearyanarun for review. Kani could not handle |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 1
Open (2)
What changed in this PR
Adds Kani support for the Rust SIMD reduction intrinsics simd_reduce_max and simd_reduce_min on integer lanes, unblocking verification of core paths (e.g., aarch64 NEON is_ascii) that lower to these intrinsics, while explicitly rejecting float-lane reductions due to unmodeled NaN semantics.
Changes:
- Implement codegen for
simd_reduce_max/simd_reduce_minover integer SIMD lanes and mark float-lane usage as unsupported. - Extend intrinsic classification (parsing, points-to, uninit checks) to recognize the new intrinsics.
- Add Kani regression tests for integer-lane behavior and expected-failure tests for float lanes; document partial support.
| File | Description |
|---|---|
| tests/kani/Intrinsics/SIMD/Reduction/reduce_min_max.rs | Adds Kani proofs validating integer-lane reduce max/min behavior against iterator max/min. |
| tests/expected/intrinsics/simd-reduce-float/main.rs | Adds harnesses that intentionally invoke float-lane reduce max/min to ensure they’re rejected. |
| tests/expected/intrinsics/simd-reduce-float/expected | Captures expected failure output for unsupported float-lane reduce max/min. |
| kani-compiler/src/kani_middle/transform/check_uninit/ptr_uninit/uninit_visitor.rs | Treats new reduce intrinsics as safe to skip for uninit pointer checking. |
| kani-compiler/src/kani_middle/points_to/points_to_analysis.rs | Treats new reduce intrinsics as identity-aliasing for points-to analysis. |
| kani-compiler/src/intrinsics.rs | Adds new intrinsic variants and matches simd_reduce_max / simd_reduce_min. |
| kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs | Implements integer-lane folding codegen and rejects float-lane reductions. |
| docs/src/rust-feature-support/intrinsics.md | Documents partial support for the two new intrinsics (integer lanes only). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
feliperodri
left a comment
There was a problem hiding this comment.
Requesting changes for one small bug; the approach is right. Integer reductions are correct for every lane width I tried (i8–u64, 1 to 16 lanes), and the aarch64 is_ascii shape (max of bytes < 0x80 ⇔ all ASCII) verifies. usize/isize lanes crash codegen on a type mismatch, which is reachable through portable SIMD's reduce_max. The cast suggested inline fixes it, and a usize harness would pin it; with that, this is an approve.
b2414f7 to
ad4abe7
Compare
|
Rebased onto main. |
ad4abe7 to
3e7d5fd
Compare
A scalar instantiation of either reduction is now reported as an unsupported construct, like the other SIMD intrinsics (model-checking#4927). Before this, it crashed the compiler in `simd_size_and_type`.
…vectors only The standard library documents both intrinsics as taking a vector of integers, and portable SIMD's float `reduce_max`/`reduce_min` fold with `max`/`min` without calling them. The comment, message, float test and docs rows now describe any other lane type as one the intrinsics do not accept.
3e7d5fd to
faaeddb
Compare
feliperodri
left a comment
There was a problem hiding this comment.
Thanks for the quick turnaround. Removing the cast brings the usize/isize crash back, and the new harnesses catch it. I also checked your float-lane reply against rustc: its LLVM backend only accepts integer lanes for these two intrinsics, so reporting floats as unsupported is the right call and there's nothing to track. Portable SIMD's reduce_max/reduce_min on usize and i64, a single-lane vector, and the is_ascii shape all verify.
One non-blocking point inline: a return type that isn't the lane type is accepted silently. rustc rejects it, and the comparisons already report it as unsupported. A follow-up is fine.
The NEON path itself only runs on verify-rust-std's macOS job, so that's the end-to-end check once this lands.
|
@srivatsansamraj ready to merge? |
|
Yes, ready once CI passes; I'll open the return-type check as a follow-up, matching |
8b51f50
…e as unsupported (model-checking#5044) Follow-up to model-checking#4934, from @feliperodri's review there. rustc rejects `simd_reduce_max` and `simd_reduce_min` when the result type is not the lane type (`E0511: expected return type 'u8' (element of input 'u8x16')`), but that check lives in rustc's codegen backend, which Kani replaces. Kani accepted such a call and cast the result, so a `u8x4` reduced into a `u32` was verified. No crate that compiles with rustc reaches this, but autoharness can, through a generic helper. This reports those calls as an unsupported construct, the way the SIMD comparisons handle an invalid mask type since model-checking#4950. Reductions with the lane type are unchanged. Testing: a new expected test, `simd-reduce-result-type`, reduces a `u8x4` into a `u32` and an `i8` and expects both harnesses to fail as unsupported. With the check removed, both harnesses verify and the test fails. The existing reduction tests (`simd-reduce-float`, `Intrinsics/SIMD/Reduction`) still pass. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Srivatsan Samraj <321934658+srivatsansamraj@users.noreply.github.com>


Resolves #4954.
In the nightly-2026-09-25 library that model-checking/verify-rust-std#687 syncs to,
core'sis_asciihas an aarch64 NEON path (is_ascii_neon) that callsvmaxvq_u8, which lowers tosimd_reduce_max. Kani reports that intrinsic as unsupported, soslice::ascii::verify::check_is_asciifails on the macOS runners for that sync and the ones after it.This adds
simd_reduce_maxandsimd_reduce_minfor integer lanes, next tosimd_reduce_all: the lanes are folded into a temporary that keeps the larger (or smaller) value at each step, with signedness taken from the lane type. Non-integer lanes are reported as unsupported: both intrinsics take integer vectors only, and portable SIMD's float reductions do not call them. The intrinsics table in the docs gets the two rows.The new
kanitest checks both reductions againstIterator::maxandIterator::minover symbolicu8x16andi32x4lanes (the signed lanes catch an unsigned comparison), and the newexpectedtest checks that the float lanes fail verification as unsupported. Both fail without this change. The aarch64 path itself does not build on x86_64, so the end-to-end check is verify-rust-std's macOS job.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.