Skip to content

JIT: stray block in gtNewSimdMinMaxNode clobbers needsFixup, miscompiling Min with a signed-zero constant #130831

Description

@tannergooding

While auditing gentree.cpp, I found a stray unconditional block in the min branch of gtNewSimdMinMaxNode (xarch, floating constant fast path) that clobbers the needsFixup computation:

if (isNumber)
{
    if (isScalar) { needsFixup = cnsNode->IsFloatPositiveZero(); }
    else          { needsFixup = cnsNode->IsVectorZero(); }
}
else if (isScalar) { needsFixup = cnsNode->IsFloatNegativeZero(); }
else               { needsFixup = cnsNode->IsVectorZero(); }
{
    needsFixup = cnsNode->IsVectorNegativeZero(simdBaseType);   // <-- clobbers all four cases
}

The trailing block makes the whole if/else chain dead, so needsFixup is always IsVectorNegativeZero(simdBaseType) (which is false for a scalar DblCon). For three of the four cases this yields the wrong value; when it wrongly lands false, the constant-fold fast path emits a bare MIN/MINSS without the required signed-zero fixup, on all hardware.

The correct min branch mirrors the (already-correct) max branch: the non-scalar non-number case uses IsVectorNegativeZero(simdBaseType) and the stray block is removed.

Effect

The min/max constant-fold fast path relies on needsFixup only for the finite opposite-signed-zero case (min(+0, -0) -> sign of zero); NaN cases are handled separately (operand swap for isNumber, natural propagation otherwise). So this is a signed-zero miscompile of Min with a signed-zero constant.

Repro

using System.Runtime.CompilerServices;

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static double MinNegZeroConst(double value) => double.Min(value, -0.0);

double r = MinNegZeroConst(+0.0);
// expected: -0.0   (double.Min treats -0 < +0)
// actual:   +0.0

Existing coverage in JitBlue/Runtime_98068 exercises Min/MinNumber const-folding but always pairs an operand with NaN; the finite opposite-signed-zero combination is never tested, which is why this survived. Latent on current main, found by inspection.

Note

This issue was authored with the help of GitHub Copilot.

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions