Skip to content

x86 does not preserve NaN bits in some cases #48832

Open

Description

@tannergooding

A customer reported this here: dotnet/dotnet-api-docs#2977

Take the following sample:

using System;

var xb = new byte[] { 1, 0, 0, 0, 0, 0, 0xf0, 0x7f };
var yb = new byte[] { 1, 0, 0, 0, 0, 0, 0xf8, 0x7f };

var x = BitConverter.ToDouble(xb);
var y = BitConverter.ToDouble(yb);
var z = BitConverter.Int64BitsToDouble(0x7FF0000000000001);
var w = BitConverter.Int64BitsToDouble(0x7FF8000000000001);

Console.WriteLine(Environment.Is64BitProcess);
Console.WriteLine($"{x}    {BitConverter.DoubleToInt64Bits(x):X16}");
Console.WriteLine($"{y}    {BitConverter.DoubleToInt64Bits(y):X16}");
Console.WriteLine($"{z}    {BitConverter.DoubleToInt64Bits(z):X16}");
Console.WriteLine($"{w}    {BitConverter.DoubleToInt64Bits(w):X16}");

On x86 when optimizations are disabled this returns:

False
NaN    7FF8000000000001
NaN    7FF8000000000001
NaN    7FF8000000000001
NaN    7FF8000000000001

However on x86 when optimizations are enabled this returns:

False
NaN    7FF8000000000001
NaN    7FF8000000000001
NaN    7FF0000000000001
NaN    7FF8000000000001

On x64, this returns the following in all cases:

True
NaN    7FF0000000000001
NaN    7FF8000000000001
NaN    7FF0000000000001
NaN    7FF8000000000001

I believe this likely has something to do with the x87 FPU stack normalizing the floating-point value. However, I would like to confirm that this is indeed the case.

category:correctness
theme:null-checks

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Feb 26, 2021
  2. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Feb 26, 2021
  3. removed
    untriagedNew issue has not been triaged by the area owner
    on Mar 2, 2021
  4. added this to the 6.0.0 milestone on Mar 2, 2021
  5. JulieLeeMSFT commented on Mar 2, 2021

    @JulieLeeMSFT
    Member

    @tannergooding, I assigned .NET6 for now.

  6. JulieLeeMSFT commented on Jul 26, 2021

    @JulieLeeMSFT
    Member

    Ping @tannergooding, are you working on this for .NET 6?

  7. tannergooding commented on Aug 10, 2021

    @tannergooding
    MemberAuthor

    Sorry for the delay, I missed the initial ping as I was on vacation at the time.

    No, this is not being worked on for 6 as its not a regression. It just represents potentially undesirable behavior.

    It’s also not clear yet if we want to take a fix here. Customers generally shouldn’t be relying on the NaN payload as per IEEE 754-2008 and -2019, which under "Reproducible floating-point results" state:

    Users obtain the same floating-point numerical and reproducible status flag results, on all platforms
    supporting such a language standard, by writing programs that:
    ...
    Do not use signaling NaNs.
    Do not depend on quiet NaN propagation, payloads, or sign bits.

    Fixing this may also hinder our own ability to take advantage of this in the future and to introduce optimizations or constant folding in such scenarios.

  8. JulieLeeMSFT commented on Aug 10, 2021

    @JulieLeeMSFT
    Member

    Thanks. Will move this to future.

  9. modified the milestones: 6.0.0, 7.0.0, Future on Aug 10, 2021
  10. added
    Priority:2Work that is important, but not critical for the release
    on Aug 10, 2021
  11. AndyAyersMS commented on Aug 12, 2026

    @AndyAyersMS
    Member

    The reported behavior is expected on x86. Floating-point values are returned through the x87 stack, and fld may quiet signaling NaNs. Optimization and inlining can therefore affect when the signaling bit is cleared.

    #75338 also intentionally quiets signaling NaNs stored as JIT IR constants on x86 to avoid configuration-dependent behavior. IEEE 754 does not guarantee preservation of the signaling bit, sign, or payload for reproducible floating-point results.

    The documentation aspect remains tracked by dotnet/dotnet-api-docs#2977. Suggest closing this as by design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Priority:2Work that is important, but not critical for the releasearea-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions