Skip to content

Commit 79d5e09

Browse files
Updating a few BitConverter APIs to be intrinsic (#71567)
* Updating a few BitConverter APIs to be intrinsic * Reacting to PR feedback * Update src/coreclr/jit/valuenum.cpp Co-authored-by: SingleAccretion <[email protected]> * Update src/coreclr/jit/gentree.h Co-authored-by: SingleAccretion <[email protected]> * Apply formatting patch * Ensure DoubleToInt64Bits and Int64BitsToDouble intrinsics only pop when appropriate * Fix VNForBitCast to not handle exception set logic since its always a normal value now * Applying formatting patch Co-authored-by: SingleAccretion <[email protected]>
1 parent 8b19573 commit 79d5e09

File tree

11 files changed

+306
-68
lines changed

11 files changed

+306
-68
lines changed

src/coreclr/jit/codegenxarch.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -490,19 +490,24 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
490490

491491
case GT_CNS_DBL:
492492
{
493-
emitter* emit = GetEmitter();
494-
emitAttr size = emitTypeSize(targetType);
495-
double constValue = tree->AsDblCon()->gtDconVal;
493+
emitter* emit = GetEmitter();
494+
emitAttr size = emitTypeSize(targetType);
496495

497-
// Make sure we use "xorps reg, reg" only for +ve zero constant (0.0) and not for -ve zero (-0.0)
498-
if (*(__int64*)&constValue == 0)
496+
if (tree->IsFloatPositiveZero())
499497
{
500-
// A faster/smaller way to generate 0
498+
// A faster/smaller way to generate Zero
501499
emit->emitIns_R_R(INS_xorps, size, targetReg, targetReg);
502500
}
501+
else if (tree->IsFloatAllBitsSet())
502+
{
503+
// A faster/smaller way to generate AllBitsSet
504+
emit->emitIns_R_R(INS_pcmpeqd, size, targetReg, targetReg);
505+
}
503506
else
504507
{
505-
CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(constValue, size);
508+
double cns = tree->AsDblCon()->gtDconVal;
509+
CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns, size);
510+
506511
emit->emitIns_R_C(ins_Load(targetType), size, targetReg, hnd, 0);
507512
}
508513
}

src/coreclr/jit/compiler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4872,6 +4872,9 @@ class Compiler
48724872
// Does value-numbering for a cast tree.
48734873
void fgValueNumberCastTree(GenTree* tree);
48744874

4875+
// Does value-numbering for a bitcast tree.
4876+
void fgValueNumberBitCast(GenTree* tree);
4877+
48754878
// Does value-numbering for an intrinsic tree.
48764879
void fgValueNumberIntrinsic(GenTree* tree);
48774880

src/coreclr/jit/gentree.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4567,9 +4567,10 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
45674567
{
45684568
level = 0;
45694569
#if defined(TARGET_XARCH)
4570-
if (tree->IsFloatPositiveZero())
4570+
if (tree->IsFloatPositiveZero() || tree->IsFloatAllBitsSet())
45714571
{
4572-
// We generate `xorp* tgtReg, tgtReg` which is 3-5 bytes
4572+
// We generate `xorp* tgtReg, tgtReg` for PositiveZero and
4573+
// `pcmpeqd tgtReg, tgtReg` for AllBitsSet which is 3-5 bytes
45734574
// but which can be elided by the instruction decoder.
45744575

45754576
costEx = 1;

src/coreclr/jit/gentree.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,7 @@ struct GenTree
18281828
#endif // DEBUG
18291829

18301830
inline bool IsIntegralConst(ssize_t constVal) const;
1831+
inline bool IsFloatAllBitsSet() const;
18311832
inline bool IsFloatNaN() const;
18321833
inline bool IsFloatPositiveZero() const;
18331834
inline bool IsFloatNegativeZero() const;
@@ -8458,6 +8459,33 @@ inline bool GenTree::IsIntegralConst(ssize_t constVal) const
84588459
return false;
84598460
}
84608461

8462+
//-------------------------------------------------------------------
8463+
// IsFloatAllBitsSet: returns true if this is exactly a const float value representing AllBitsSet.
8464+
//
8465+
// Returns:
8466+
// True if this represents a const floating-point value representing AllBitsSet.
8467+
// Will return false otherwise.
8468+
//
8469+
inline bool GenTree::IsFloatAllBitsSet() const
8470+
{
8471+
if (IsCnsFltOrDbl())
8472+
{
8473+
double constValue = AsDblCon()->gtDconVal;
8474+
8475+
if (TypeIs(TYP_FLOAT))
8476+
{
8477+
return FloatingPointUtils::isAllBitsSet(static_cast<float>(constValue));
8478+
}
8479+
else
8480+
{
8481+
assert(TypeIs(TYP_DOUBLE));
8482+
return FloatingPointUtils::isAllBitsSet(constValue);
8483+
}
8484+
}
8485+
8486+
return false;
8487+
}
8488+
84618489
//-------------------------------------------------------------------
84628490
// IsFloatNaN: returns true if this is exactly a const float value of NaN
84638491
//
@@ -8509,7 +8537,7 @@ inline bool GenTree::IsFloatPositiveZero() const
85098537
// but it is easier to parse out
85108538
// rather than using !IsCnsNonZeroFltOrDbl.
85118539
double constValue = AsDblCon()->gtDconVal;
8512-
return *(__int64*)&constValue == 0;
8540+
return FloatingPointUtils::isPositiveZero(constValue);
85138541
}
85148542

85158543
return false;

src/coreclr/jit/importer.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,6 +4880,96 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
48804880
break;
48814881
}
48824882

4883+
case NI_System_BitConverter_DoubleToInt64Bits:
4884+
{
4885+
GenTree* op1 = impStackTop().val;
4886+
assert(varTypeIsFloating(op1));
4887+
4888+
if (op1->IsCnsFltOrDbl())
4889+
{
4890+
impPopStack();
4891+
4892+
double f64Cns = op1->AsDblCon()->gtDconVal;
4893+
retNode = gtNewLconNode(*reinterpret_cast<int64_t*>(&f64Cns));
4894+
}
4895+
#if TARGET_64BIT
4896+
else
4897+
{
4898+
// TODO-Cleanup: We should support this on 32-bit but it requires decomposition work
4899+
impPopStack();
4900+
4901+
if (op1->TypeGet() != TYP_DOUBLE)
4902+
{
4903+
op1 = gtNewCastNode(TYP_DOUBLE, op1, false, TYP_DOUBLE);
4904+
}
4905+
retNode = gtNewBitCastNode(TYP_LONG, op1);
4906+
}
4907+
#endif
4908+
break;
4909+
}
4910+
4911+
case NI_System_BitConverter_Int32BitsToSingle:
4912+
{
4913+
GenTree* op1 = impPopStack().val;
4914+
assert(varTypeIsInt(op1));
4915+
4916+
if (op1->IsIntegralConst())
4917+
{
4918+
int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue();
4919+
retNode = gtNewDconNode(*reinterpret_cast<float*>(&i32Cns), TYP_FLOAT);
4920+
}
4921+
else
4922+
{
4923+
retNode = gtNewBitCastNode(TYP_FLOAT, op1);
4924+
}
4925+
break;
4926+
}
4927+
4928+
case NI_System_BitConverter_Int64BitsToDouble:
4929+
{
4930+
GenTree* op1 = impStackTop().val;
4931+
assert(varTypeIsLong(op1));
4932+
4933+
if (op1->IsIntegralConst())
4934+
{
4935+
impPopStack();
4936+
4937+
int64_t i64Cns = op1->AsIntConCommon()->LngValue();
4938+
retNode = gtNewDconNode(*reinterpret_cast<double*>(&i64Cns));
4939+
}
4940+
#if TARGET_64BIT
4941+
else
4942+
{
4943+
// TODO-Cleanup: We should support this on 32-bit but it requires decomposition work
4944+
impPopStack();
4945+
4946+
retNode = gtNewBitCastNode(TYP_DOUBLE, op1);
4947+
}
4948+
#endif
4949+
break;
4950+
}
4951+
4952+
case NI_System_BitConverter_SingleToInt32Bits:
4953+
{
4954+
GenTree* op1 = impPopStack().val;
4955+
assert(varTypeIsFloating(op1));
4956+
4957+
if (op1->IsCnsFltOrDbl())
4958+
{
4959+
float f32Cns = (float)op1->AsDblCon()->gtDconVal;
4960+
retNode = gtNewIconNode(*reinterpret_cast<int32_t*>(&f32Cns));
4961+
}
4962+
else
4963+
{
4964+
if (op1->TypeGet() != TYP_FLOAT)
4965+
{
4966+
op1 = gtNewCastNode(TYP_FLOAT, op1, false, TYP_FLOAT);
4967+
}
4968+
retNode = gtNewBitCastNode(TYP_INT, op1);
4969+
}
4970+
break;
4971+
}
4972+
48834973
default:
48844974
break;
48854975
}
@@ -5518,6 +5608,53 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
55185608
result = NI_System_Activator_DefaultConstructorOf;
55195609
}
55205610
}
5611+
else if (strcmp(className, "BitConverter") == 0)
5612+
{
5613+
if (methodName[0] == 'D')
5614+
{
5615+
if (strcmp(methodName, "DoubleToInt64Bits") == 0)
5616+
{
5617+
result = NI_System_BitConverter_DoubleToInt64Bits;
5618+
}
5619+
else if (strcmp(methodName, "DoubleToUInt64Bits") == 0)
5620+
{
5621+
result = NI_System_BitConverter_DoubleToInt64Bits;
5622+
}
5623+
}
5624+
else if (methodName[0] == 'I')
5625+
{
5626+
if (strcmp(methodName, "Int32BitsToSingle") == 0)
5627+
{
5628+
result = NI_System_BitConverter_Int32BitsToSingle;
5629+
}
5630+
else if (strcmp(methodName, "Int64BitsToDouble") == 0)
5631+
{
5632+
result = NI_System_BitConverter_Int64BitsToDouble;
5633+
}
5634+
}
5635+
else if (methodName[0] == 'S')
5636+
{
5637+
if (strcmp(methodName, "SingleToInt32Bits") == 0)
5638+
{
5639+
result = NI_System_BitConverter_SingleToInt32Bits;
5640+
}
5641+
else if (strcmp(methodName, "SingleToUInt32Bits") == 0)
5642+
{
5643+
result = NI_System_BitConverter_SingleToInt32Bits;
5644+
}
5645+
}
5646+
else if (methodName[0] == 'U')
5647+
{
5648+
if (strcmp(methodName, "UInt32BitsToSingle") == 0)
5649+
{
5650+
result = NI_System_BitConverter_Int32BitsToSingle;
5651+
}
5652+
else if (strcmp(methodName, "UInt64BitsToDouble") == 0)
5653+
{
5654+
result = NI_System_BitConverter_Int64BitsToDouble;
5655+
}
5656+
}
5657+
}
55215658
else if (strcmp(className, "Math") == 0 || strcmp(className, "MathF") == 0)
55225659
{
55235660
if (strcmp(methodName, "Abs") == 0)

src/coreclr/jit/namedintrinsiclist.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ enum NamedIntrinsic : unsigned short
1515

1616
NI_System_Enum_HasFlag,
1717

18+
NI_System_BitConverter_DoubleToInt64Bits,
19+
NI_System_BitConverter_Int32BitsToSingle,
20+
NI_System_BitConverter_Int64BitsToDouble,
21+
NI_System_BitConverter_SingleToInt32Bits,
22+
1823
NI_SYSTEM_MATH_START,
1924
NI_System_Math_Abs,
2025
NI_System_Math_Acos,

src/coreclr/jit/utils.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,38 @@ bool FloatingPointUtils::hasPreciseReciprocal(float x)
22322232
return mantissa == 0 && exponent != 0 && exponent != 127;
22332233
}
22342234

2235+
//------------------------------------------------------------------------
2236+
// isAllBitsSet: Determines whether the specified value is AllBitsSet
2237+
//
2238+
// Arguments:
2239+
// val - value to check for AllBitsSet
2240+
//
2241+
// Return Value:
2242+
// True if val is AllBitsSet
2243+
//
2244+
2245+
bool FloatingPointUtils::isAllBitsSet(float val)
2246+
{
2247+
UINT32 bits = *reinterpret_cast<UINT32*>(&val);
2248+
return bits == 0xFFFFFFFFU;
2249+
}
2250+
2251+
//------------------------------------------------------------------------
2252+
// isAllBitsSet: Determines whether the specified value is AllBitsSet
2253+
//
2254+
// Arguments:
2255+
// val - value to check for AllBitsSet
2256+
//
2257+
// Return Value:
2258+
// True if val is AllBitsSet
2259+
//
2260+
2261+
bool FloatingPointUtils::isAllBitsSet(double val)
2262+
{
2263+
UINT64 bits = *reinterpret_cast<UINT64*>(&val);
2264+
return bits == 0xFFFFFFFFFFFFFFFFULL;
2265+
}
2266+
22352267
//------------------------------------------------------------------------
22362268
// isNegative: Determines whether the specified value is negative
22372269
//
@@ -2310,6 +2342,22 @@ bool FloatingPointUtils::isNegativeZero(double val)
23102342
return bits == 0x8000000000000000ULL;
23112343
}
23122344

2345+
//------------------------------------------------------------------------
2346+
// isPositiveZero: Determines whether the specified value is positive zero (+0.0)
2347+
//
2348+
// Arguments:
2349+
// val - value to check for (+0.0)
2350+
//
2351+
// Return Value:
2352+
// True if val is (+0.0)
2353+
//
2354+
2355+
bool FloatingPointUtils::isPositiveZero(double val)
2356+
{
2357+
UINT64 bits = *reinterpret_cast<UINT64*>(&val);
2358+
return bits == 0x0000000000000000ULL;
2359+
}
2360+
23132361
//------------------------------------------------------------------------
23142362
// maximum: This matches the IEEE 754:2019 `maximum` function
23152363
// It propagates NaN inputs back to the caller and

src/coreclr/jit/utils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,10 @@ class FloatingPointUtils
703703

704704
static float infinite_float();
705705

706+
static bool isAllBitsSet(float val);
707+
708+
static bool isAllBitsSet(double val);
709+
706710
static bool isNegative(float val);
707711

708712
static bool isNegative(double val);
@@ -713,6 +717,8 @@ class FloatingPointUtils
713717

714718
static bool isNegativeZero(double val);
715719

720+
static bool isPositiveZero(double val);
721+
716722
static double maximum(double val1, double val2);
717723

718724
static float maximum(float val1, float val2);

0 commit comments

Comments
 (0)