Skip to content

Commit d600dbc

Browse files
committed
Fix: Only skip AND masking for unsigned narrow types in NarrowWithSaturation
The inputsAlreadyClamped optimization was incorrectly applied to all types, but it's only valid for unsigned narrow types (TYP_UBYTE, TYP_USHORT). For signed narrow types, the AND masking is still required to clear the sign-extended upper bits before PackUnsignedSaturate can correctly pack the values. Without this masking, negative values would have incorrect upper bits that would cause PackUnsignedSaturate to produce wrong results. This fixes System.Numerics.Tests.GenericVectorTests.NarrowWithSaturationInt32Test
1 parent 129c83b commit d600dbc

1 file changed

Lines changed: 8 additions & 2 deletions

File tree

src/coreclr/jit/hwintrinsicxarch.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,8 +3541,14 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
35413541
op2 = gtNewSimdMinMaxNode(retType, op2, gtCloneExpr(maxCns), simdBaseType, simdSize,
35423542
/* isMax */ false, /* isMagnitude */ false, /* isNumber */ false);
35433543

3544-
retNode = gtNewSimdNarrowNode(retType, op1, op2, narrowSimdBaseType, simdSize,
3545-
/* inputsAlreadyClamped */ true);
3544+
// For unsigned narrow types (TYP_UBYTE, TYP_USHORT), the clamping already ensures
3545+
// the upper bits are zero, so the AND masking in gtNewSimdNarrowNode is redundant.
3546+
// For signed narrow types, we still need the AND masking to clear sign-extended bits
3547+
// before PackUnsignedSaturate can correctly pack the values.
3548+
bool inputsAlreadyClamped = varTypeIsUnsigned(narrowSimdBaseType);
3549+
3550+
retNode =
3551+
gtNewSimdNarrowNode(retType, op1, op2, narrowSimdBaseType, simdSize, inputsAlreadyClamped);
35463552
}
35473553
}
35483554
break;

0 commit comments

Comments
 (0)