Skip to content

Decide and document where stdarch intrinsics are allowed to diverge from asm behavior #153990

@RalfJung

Description

@RalfJung

stdarch has started using the simd_* LLVM intrinsics for many operations, which is great news for backends like cranelift and Miri. However, it also means we get extra optimizations that would otherwise not apply: LLVM will constant-fold these operations using its usual NaN rules, which means that the sign and payload of a NaN can be different from what would happen if the vendor intrinsic was implemented by an inline assembly block. Furthermore, SNaNs can be non-deterministically treated like QNaNs, which can make a difference for operations where QNaN input lead to non-NaN results.

Which differences are acceptable?

  • I assume we definitely want to tolerate differences in NaN payloads/signs. Without that, we couldn't use any portable SIMD operations in stdarch. Arguably, this is already covered by the existing general float NaN docs, though not everyone might expect that to apply even to vendor intrinsics.
  • What about differences in whether a NaN is returned? This is relevant e.g. for some variants of min/max where the vendor may say that an SNaN input always produces a NaN result, but the portable LLVM intrinsic makes no such guarantee and could produce a non-NaN result. See Revert "Merge pull request #1871 from folkertdev/aarch64-float-min-max" stdarch#2052 for a concrete example where such SNaN behavior was fixed.
  • On targets like ARM32 where subnormal numbers do not work properly for SIMD vectors, we might also see differences in the actual numerical results -- if LLVM constant-folds those operations, that will be done with proper subnormal support. In fact, LLVM itself mistreats those operations on ARM32, leading to miscompilations (32-bit ARM NEON intrinsics are unsound due to subnormal flushing #129880).

Currently, I don't think we properly document this anywhere? It doesn't seem too unlikely that someone might expect the vendor intrinsics to always behave exactly like the corresponding asm instructions, so we better clarify the expectations here. Once a decision has been made, the module-level docs might be a good place to document this.
Cc @rust-lang/libs-api

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions