Skip to content

Report a SIMD intrinsic monomorphized with a scalar instead of crashing - #4927

Merged
tautschnig merged 6 commits into
model-checking:mainfrom
feliperodri:fix-4919-simd-scalar
Oct 2, 2026
Merged

tautschnig merged 6 commits into
model-checking:mainfrom
feliperodri:fix-4919-simd-scalar

Conversation

@feliperodri

@feliperodri feliperodri commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

-Z autoharness crashed the compiler on a generic helper whose body calls a SIMD intrinsic but whose type parameter carries no SIMD bound. Autoharness picked T = i32, and the SIMD comparison codegen unwrapped the vector length of a scalar. core_arch::simd::simd_imin<T: Copy> has exactly this shape, so core failed codegen, which is what blocks the unfiltered autoharness path in model-checking/verify-rust-std#687.

Update after merging main: #4922 has since added the codegen guard (the crash no longer happens on main; the call is reported as an unsupported construct), so this PR is now the autoharness side of that fix: it stops autoharness from choosing such instantiations in the first place.

rustc's codegen backends reject these monomorphizations (E0511: invalid monomorphization of simd_ltintrinsic: expected SIMD input type, found non-SIMDi32``), but Kani replaces the backend, so such calls reach Kani's codegen: from a harness that calls imin::<i32> directly, and from instantiations that autoharness synthesizes.

Codegen. #4922's guard is kept as is (behaviour, message and issue link); its inline list of the 21 SIMD intrinsics is replaced by Intrinsic::simd_vector_operand, which names the operand that must be a vector and lives next to try_match_simd, so a new SIMD intrinsic is added in one place and the autoharness filter below uses the same list. simd_splat is the only one whose vector is the return type rather than the first argument.

Autoharness stops choosing those instantiations. A candidate type is rejected when it would make a SIMD intrinsic call in the function's own body invalid. On the reproducer this is better than skipping: autoharness moves on and picks the #[repr(simd)] type, so imin is verified rather than reported. Where no candidate is SIMD, the function is skipped with a reason that names the intrinsic instead of blaming trait bounds the candidate does satisfy.

What it deliberately leaves. A generic function that reaches the invalid instantiation one level down, through a call, is still only caught in codegen, so its harness fails rather than being skipped. Detecting that needs a transitive walk with composed substitutions, like has_const_generic_precondition does for const blocks; filed as #4926, and the new test pins the current behaviour so that fix has to update it.

Testing. tests/script-based-pre/autoharness_simd_non_simd_instantiation covers the reproducer, the one-level-down case, and a function whose SIMD operand types are fixed (unaffected). I confirmed it fails without the fix, and that a deliberately wrong expectation fails the test. After merging main: the test, all 39 script-based-pre autoharness tests, the expected SIMD tests (including #4922's simd-scalar-operand) and the kani SIMD tests pass, as do fmt and both clippy invocations. The kani, expected, ui, cargo-kani and script-based-pre suites pass, as do fmt and clippy.

One thing worth a reviewer's eye: the candidate check calls instance.body(), which skip_reason then calls again for the chosen instance, so a generic function now costs one extra stable-MIR conversion. It happens only for candidates that already satisfy the predicates, which is normally one per function, and rustc caches the underlying monomorphization — but say if you would rather it were hoisted or pre-filtered.

I could not confirm the core case end to end locally: simd_imin is present in the pinned toolchain's stdarch, but kani autoharness --std failed while building compiler_builtins, before reaching any Kani code. The evidence here is that the test reproduces the same shape.

Follow-up to #4922, which resolved #4919.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

`ty_validity`-style `unwrap`s in the SIMD codegen read a vector length
that a scalar does not have, so `-Z autoharness` aborted the whole run on
a generic helper whose type parameter carries no SIMD bound -- the shape
`core_arch::simd::simd_imin` has, which blocked autoharness over the
standard library.

rustc rejects such a monomorphization with E0511, so no call site in a
program that compiles reaches codegen this way; autoharness synthesizes
the instantiation itself. Fix both ends:

- One guard covers all 21 SIMD intrinsics: when the operand that must be
  a vector is not one, report it against the harness that reached it
  rather than unwrapping. `simd_splat` is the one whose vector is the
  return type instead of the first argument.
- Autoharness rejects a candidate type that would make a SIMD intrinsic
  call invalid, so it picks a SIMD type where one is available and skips
  the function with a specific reason otherwise.

Resolves model-checking#4919
@feliperodri
feliperodri requested review from a team as code owners September 30, 2026 15:55
@github-actions github-actions Bot added Z-EndToEndBenchCI Tag a PR to run benchmark CI Z-CompilerBenchCI Tag a PR to run benchmark CI labels Sep 30, 2026
tautschnig and others added 2 commits October 1, 2026 11:43
Resolve the conflict with model-checking#4922's guard in `codegen_intrinsic` by keeping
main's behaviour, message and issue link, with its inline list of SIMD
intrinsics replaced by `Intrinsic::simd_vector_operand` (the same 21
intrinsics), which the autoharness filter shares. The test's expected
message follows main's wording, which model-checking#4922's
`expected/intrinsics/simd-scalar-operand` test pins.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
…calar

`E0511` (`invalid monomorphization of `simd_lt` intrinsic: expected SIMD
input type, found non-SIMD `i32``) comes from rustc's codegen backends
(`InvalidMonomorphization::SimdInput` in `rustc_codegen_ssa`), and
type-checking the intrinsic puts no SIMD bound on its parameter. Kani
replaces the backend, so an ordinary source call with a scalar does reach
Kani's codegen (model-checking#4922's `simd-scalar-operand` test is one). Correct the
doc comments that said such a call cannot occur in source code.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The shared guard, candidate filtering, diagnostics, and regression coverage consistently implement the stated behavior.

Review effort: Balanced
Findings: None

What changed in this PR

Prevents autoharness from selecting scalar monomorphizations for directly called SIMD intrinsics, complementing #4922’s codegen guard.

Changes:

  • Centralizes SIMD vector-operand identification.
  • Filters invalid autoharness candidates while preserving the documented transitive limitation.
  • Adds regression coverage for direct, transitive, and fixed-type SIMD calls.
File Description
kani-compiler/​src/​intrinsics.rs Centralizes SIMD vector-operand selection.
kani-compiler/​src/​kani_middle/​codegen_units.rs Rejects invalid scalar SIMD candidates.
kani-compiler/​src/​codegen_cprover_gotoc/​codegen/​intrinsic.rs Reuses the shared SIMD operand helper.
tests/​script-based-pre/​autoharness_simd_non_simd_instantiation/​simd_generic.rs Defines regression scenarios.
tests/​script-based-pre/​autoharness_simd_non_simd_instantiation/​check.sh Validates harness selection and completion.
tests/​script-based-pre/​autoharness_simd_non_simd_instantiation/​config.yml Registers the script-based test.
tests/​script-based-pre/​autoharness_simd_non_simd_instantiation/​expected Records expected test output.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@tautschnig
tautschnig enabled auto-merge October 2, 2026 13:50
Resolve the conflict with model-checking#4880 at the end of the generic instantiation
search: try main's uniform `()` fallback first (it, too, goes through the
SIMD check, which rejects `()` for a SIMD operand), then report a SIMD
rejection, the more specific reason, ahead of model-checking#4880's attempt-limit
message and the generic "no candidate type" one.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
@tautschnig
tautschnig added this pull request to the merge queue Oct 2, 2026
Merged via the queue into model-checking:main with commit 5193da6 Oct 2, 2026
33 of 34 checks passed
kasimte pushed a commit to kasimte/kani that referenced this pull request Oct 3, 2026
…odel-checking#4951)

Autoharness over the standard library still aborts on
`core_arch::simd::simd_imax<T: Copy>`. After model-checking#4927 it no longer picks a
scalar for `T`, but it can pick `__m128`, a SIMD type with `f32` lanes.
The body stores `simd_gt`'s result in `T`, and a comparison's result is
a mask that needs integer lanes, so Kani's codegen raised a compile
error. A compile error aborts the whole crate, so this one function
stopped every harness. It is the last compile-time blocker for the
unfiltered autoharness jobs in model-checking/verify-rust-std#687 (see
model-checking#4950).

The fix has two parts, in the same shape as model-checking#4927:

**Autoharness rejects the instantiation.** A candidate is now rejected
when its body makes a SIMD comparison return anything other than an
integer-lane vector with as many lanes as the operands. Autoharness then
keeps searching. When an integer SIMD type also satisfies the bounds, it
picks that one and the function is verified; otherwise the function is
skipped with a reason that names the comparison and the lane type.

**Codegen no longer aborts the crate.** An invalid comparison result
type is now reported as an unsupported construct, which fails only the
harnesses that reach it. This is the backstop for the case autoharness
can't see: a generic function that reaches the invalid comparison one
level down (model-checking#4926).

**The behaviour change to weigh.** Under Kani, rustc's codegen backend
never runs, so these checks are the only stand-in for rustc's `E0511`.
Before this PR, a comparison written directly with an invalid result
type, like `let m: f32x2 = simd_eq(x, y)`, was a compile error. Now it
compiles, and verification fails if the comparison is reachable. Such a
program can't be built by rustc at all, so verifying it says nothing
about a real executable, but the diagnostic moves from compile time to
verification time. The two tests that pinned the compile error
(`simd-result-type-is-float`, `simd-cmp-result-type-is-diff-size`) now
pin the unsupported check. If you'd rather keep the compile error for
directly written code, the autoharness half is enough for the reported
case; only the one-level-down case would still abort.

**Scope.** I only changed the comparison checks. `simd_splat`,
`simd_extract`, `simd_insert` and `simd_shuffle` have the same
compile-error-aborts-the-crate shape, but nothing in the standard
library reaches them this way today. Filed as model-checking#4952 rather than widening
this PR.

**Testing.**
- New `tests/script-based-pre/autoharness_simd_cmp_float_lanes` checks
three things: a float-only candidate is skipped with the reason; with a
float and an integer type available, autoharness picks the integer one
and it verifies; and the one-level-down case fails its own harness while
the run completes. The test fails without the compiler change.
- Locally, merged with current `main`: `expected` (498), `kani` (620),
`script-based-pre` (91), `ui` (152) and `cargo-kani` (71) pass, as do
fmt and clippy, both for the workspace and with `--features llbc`.
- Not run with this exact branch: the full standard-library autoharness.
For model-checking#4950 I ran the equivalent codegen change against verify-rust-std's
`library/`, and the run completed with no panics; this branch adds the
autoharness rejection on top.

Resolves model-checking#4950

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
srivatsansamraj added a commit to srivatsansamraj/kani that referenced this pull request Oct 5, 2026
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`.
srivatsansamraj added a commit to srivatsansamraj/kani that referenced this pull request Oct 6, 2026
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`.
srivatsansamraj added a commit to srivatsansamraj/kani that referenced this pull request Oct 9, 2026
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`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Z-CompilerBenchCI Tag a PR to run benchmark CI Z-EndToEndBenchCI Tag a PR to run benchmark CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Autoharness ICE: SIMD codegen unwraps vector length for a generic helper instantiated with a scalar

4 participants