@@ -363,6 +363,11 @@ typedef simd64_t simd_t;
363
363
typedef simd16_t simd_t ;
364
364
#endif
365
365
366
+ inline bool IsUnaryBitwiseOperation (genTreeOps oper)
367
+ {
368
+ return (oper == GT_LZCNT) || (oper == GT_NOT);
369
+ }
370
+
366
371
template <typename TBase>
367
372
TBase EvaluateUnaryScalarSpecialized (genTreeOps oper, TBase arg0)
368
373
{
@@ -404,27 +409,35 @@ TBase EvaluateUnaryScalarSpecialized(genTreeOps oper, TBase arg0)
404
409
template <>
405
410
inline float EvaluateUnaryScalarSpecialized<float >(genTreeOps oper, float arg0)
406
411
{
407
- if (oper == GT_NEG )
412
+ switch (oper)
408
413
{
409
- return -arg0;
410
- }
414
+ case GT_NEG:
415
+ {
416
+ return -arg0;
417
+ }
411
418
412
- uint32_t arg0Bits = BitOperations::SingleToUInt32Bits (arg0);
413
- uint32_t resultBits = EvaluateUnaryScalarSpecialized<uint32_t >(oper, arg0Bits);
414
- return BitOperations::UInt32BitsToSingle (resultBits);
419
+ default :
420
+ {
421
+ unreached ();
422
+ }
423
+ }
415
424
}
416
425
417
426
template <>
418
427
inline double EvaluateUnaryScalarSpecialized<double >(genTreeOps oper, double arg0)
419
428
{
420
- if (oper == GT_NEG )
429
+ switch (oper)
421
430
{
422
- return -arg0;
423
- }
431
+ case GT_NEG:
432
+ {
433
+ return -arg0;
434
+ }
424
435
425
- uint64_t arg0Bits = BitOperations::DoubleToUInt64Bits (arg0);
426
- uint64_t resultBits = EvaluateUnaryScalarSpecialized<uint64_t >(oper, arg0Bits);
427
- return BitOperations::UInt64BitsToDouble (resultBits);
436
+ default :
437
+ {
438
+ unreached ();
439
+ }
440
+ }
428
441
}
429
442
430
443
template <typename TBase>
@@ -600,13 +613,37 @@ void EvaluateUnarySimd(genTreeOps oper, bool scalar, var_types baseType, TSimd*
600
613
{
601
614
case TYP_FLOAT:
602
615
{
603
- EvaluateUnarySimd<TSimd, float >(oper, scalar, result, arg0);
616
+ // Some operations are bitwise and we want to ensure inputs like
617
+ // sNaN are preserved rather than being converted to a qNaN when
618
+ // the CPU encounters them. So we check for and handle that early
619
+ // prior to extracting the element out of the vector value.
620
+
621
+ if (IsUnaryBitwiseOperation (oper))
622
+ {
623
+ EvaluateUnarySimd<TSimd, int32_t >(oper, scalar, result, arg0);
624
+ }
625
+ else
626
+ {
627
+ EvaluateUnarySimd<TSimd, float >(oper, scalar, result, arg0);
628
+ }
604
629
break ;
605
630
}
606
631
607
632
case TYP_DOUBLE:
608
633
{
609
- EvaluateUnarySimd<TSimd, double >(oper, scalar, result, arg0);
634
+ // Some operations are bitwise and we want to ensure inputs like
635
+ // sNaN are preserved rather than being converted to a qNaN when
636
+ // the CPU encounters them. So we check for and handle that early
637
+ // prior to extracting the element out of the vector value.
638
+
639
+ if (IsUnaryBitwiseOperation (oper))
640
+ {
641
+ EvaluateUnarySimd<TSimd, int64_t >(oper, scalar, result, arg0);
642
+ }
643
+ else
644
+ {
645
+ EvaluateUnarySimd<TSimd, double >(oper, scalar, result, arg0);
646
+ }
610
647
break ;
611
648
}
612
649
@@ -665,6 +702,12 @@ void EvaluateUnarySimd(genTreeOps oper, bool scalar, var_types baseType, TSimd*
665
702
}
666
703
}
667
704
705
+ inline bool IsBinaryBitwiseOperation (genTreeOps oper)
706
+ {
707
+ return (oper == GT_AND) || (oper == GT_AND_NOT) || (oper == GT_LSH) || (oper == GT_OR) || (oper == GT_ROL) ||
708
+ (oper == GT_ROR) || (oper == GT_RSH) || (oper == GT_RSZ) || (oper == GT_XOR);
709
+ }
710
+
668
711
template <typename TBase>
669
712
TBase EvaluateBinaryScalarRSZ (TBase arg0, TBase arg1)
670
713
{
@@ -902,11 +945,7 @@ inline float EvaluateBinaryScalarSpecialized<float>(genTreeOps oper, float arg0,
902
945
903
946
default :
904
947
{
905
- uint32_t arg0Bits = BitOperations::SingleToUInt32Bits (arg0);
906
- uint32_t arg1Bits = BitOperations::SingleToUInt32Bits (arg1);
907
-
908
- uint32_t resultBits = EvaluateBinaryScalarSpecialized<uint32_t >(oper, arg0Bits, arg1Bits);
909
- return BitOperations::UInt32BitsToSingle (resultBits);
948
+ unreached ();
910
949
}
911
950
}
912
951
}
@@ -948,11 +987,7 @@ inline double EvaluateBinaryScalarSpecialized<double>(genTreeOps oper, double ar
948
987
949
988
default :
950
989
{
951
- uint64_t arg0Bits = BitOperations::DoubleToUInt64Bits (arg0);
952
- uint64_t arg1Bits = BitOperations::DoubleToUInt64Bits (arg1);
953
-
954
- uint64_t resultBits = EvaluateBinaryScalarSpecialized<uint64_t >(oper, arg0Bits, arg1Bits);
955
- return BitOperations::UInt64BitsToDouble (resultBits);
990
+ unreached ();
956
991
}
957
992
}
958
993
}
@@ -1188,13 +1223,37 @@ void EvaluateBinarySimd(
1188
1223
{
1189
1224
case TYP_FLOAT:
1190
1225
{
1191
- EvaluateBinarySimd<TSimd, float >(oper, scalar, result, arg0, arg1);
1226
+ // Some operations are bitwise and we want to ensure inputs like
1227
+ // sNaN are preserved rather than being converted to a qNaN when
1228
+ // the CPU encounters them. So we check for and handle that early
1229
+ // prior to extracting the element out of the vector value.
1230
+
1231
+ if (IsBinaryBitwiseOperation (oper))
1232
+ {
1233
+ EvaluateBinarySimd<TSimd, int32_t >(oper, scalar, result, arg0, arg1);
1234
+ }
1235
+ else
1236
+ {
1237
+ EvaluateBinarySimd<TSimd, float >(oper, scalar, result, arg0, arg1);
1238
+ }
1192
1239
break ;
1193
1240
}
1194
1241
1195
1242
case TYP_DOUBLE:
1196
1243
{
1197
- EvaluateBinarySimd<TSimd, double >(oper, scalar, result, arg0, arg1);
1244
+ // Some operations are bitwise and we want to ensure inputs like
1245
+ // sNaN are preserved rather than being converted to a qNaN when
1246
+ // the CPU encounters them. So we check for and handle that early
1247
+ // prior to extracting the element out of the vector value.
1248
+
1249
+ if (IsBinaryBitwiseOperation (oper))
1250
+ {
1251
+ EvaluateBinarySimd<TSimd, int64_t >(oper, scalar, result, arg0, arg1);
1252
+ }
1253
+ else
1254
+ {
1255
+ EvaluateBinarySimd<TSimd, double >(oper, scalar, result, arg0, arg1);
1256
+ }
1198
1257
break ;
1199
1258
}
1200
1259
0 commit comments