Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating a few BitConverter APIs to be intrinsic #71567

Merged
merged 10 commits into from
Jul 7, 2022
19 changes: 12 additions & 7 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,19 +490,24 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre

case GT_CNS_DBL:
{
emitter* emit = GetEmitter();
emitAttr size = emitTypeSize(targetType);
double constValue = tree->AsDblCon()->gtDconVal;
emitter* emit = GetEmitter();
emitAttr size = emitTypeSize(targetType);

// Make sure we use "xorps reg, reg" only for +ve zero constant (0.0) and not for -ve zero (-0.0)
if (*(__int64*)&constValue == 0)
if (tree->IsFloatPositiveZero())
{
// A faster/smaller way to generate 0
// A faster/smaller way to generate Zero
emit->emitIns_R_R(INS_xorps, size, targetReg, targetReg);
}
else if (tree->IsFloatAllBitsSet())
{
// A faster/smaller way to generate AllBitsSet
emit->emitIns_R_R(INS_pcmpeqd, size, targetReg, targetReg);
}
else
{
CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(constValue, size);
double cns = tree->AsDblCon()->gtDconVal;
CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns, size);

emit->emitIns_R_C(ins_Load(targetType), size, targetReg, hnd, 0);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4872,6 +4872,9 @@ class Compiler
// Does value-numbering for a cast tree.
void fgValueNumberCastTree(GenTree* tree);

// Does value-numbering for a bitcast tree.
void fgValueNumberBitCast(GenTree* tree);

// Does value-numbering for an intrinsic tree.
void fgValueNumberIntrinsic(GenTree* tree);

Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4567,9 +4567,10 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
{
level = 0;
#if defined(TARGET_XARCH)
if (tree->IsFloatPositiveZero())
if (tree->IsFloatPositiveZero() || tree->IsFloatAllBitsSet())
{
// We generate `xorp* tgtReg, tgtReg` which is 3-5 bytes
// We generate `xorp* tgtReg, tgtReg` for PositiveZero and
// `pcmpeqd tgtReg, tgtReg` for AllBitsSet which is 3-5 bytes
// but which can be elided by the instruction decoder.

costEx = 1;
Expand Down
30 changes: 29 additions & 1 deletion src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,7 @@ struct GenTree
#endif // DEBUG

inline bool IsIntegralConst(ssize_t constVal) const;
inline bool IsFloatAllBitsSet() const;
inline bool IsFloatNaN() const;
inline bool IsFloatPositiveZero() const;
inline bool IsFloatNegativeZero() const;
Expand Down Expand Up @@ -8458,6 +8459,33 @@ inline bool GenTree::IsIntegralConst(ssize_t constVal) const
return false;
}

//-------------------------------------------------------------------
// IsFloatAllBitsSet: returns true if this is exactly a const float value representing AllBitsSet.
//
// Returns:
// True if this represents a const floating-point value representing AllBitsSet.
// Will return false otherwise.
//
inline bool GenTree::IsFloatAllBitsSet() const
{
if (IsCnsFltOrDbl())
{
double constValue = AsDblCon()->gtDconVal;

if (TypeIs(TYP_FLOAT))
{
return FloatingPointUtils::isAllBitsSet(static_cast<float>(constValue));
}
else
{
assert(TypeIs(TYP_DOUBLE));
return FloatingPointUtils::isAllBitsSet(constValue);
}
}

return false;
}

//-------------------------------------------------------------------
// IsFloatNaN: returns true if this is exactly a const float value of NaN
//
Expand Down Expand Up @@ -8509,7 +8537,7 @@ inline bool GenTree::IsFloatPositiveZero() const
// but it is easier to parse out
// rather than using !IsCnsNonZeroFltOrDbl.
double constValue = AsDblCon()->gtDconVal;
return *(__int64*)&constValue == 0;
return FloatingPointUtils::isPositiveZero(constValue);
}

return false;
Expand Down
137 changes: 137 additions & 0 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4880,6 +4880,96 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
break;
}

case NI_System_BitConverter_DoubleToInt64Bits:
{
GenTree* op1 = impStackTop().val;
assert(varTypeIsFloating(op1));

if (op1->IsCnsFltOrDbl())
{
impPopStack();

double f64Cns = op1->AsDblCon()->gtDconVal;
retNode = gtNewLconNode(*reinterpret_cast<int64_t*>(&f64Cns));
}
#if TARGET_64BIT
else
{
// TODO-Cleanup: We should support this on 32-bit but it requires decomposition work
impPopStack();

if (op1->TypeGet() != TYP_DOUBLE)
{
op1 = gtNewCastNode(TYP_DOUBLE, op1, false, TYP_DOUBLE);
}
retNode = gtNewBitCastNode(TYP_LONG, op1);
}
#endif
break;
}

case NI_System_BitConverter_Int32BitsToSingle:
{
GenTree* op1 = impPopStack().val;
assert(varTypeIsInt(op1));

if (op1->IsIntegralConst())
{
int32_t i32Cns = (int32_t)op1->AsIntConCommon()->IconValue();
retNode = gtNewDconNode(*reinterpret_cast<float*>(&i32Cns), TYP_FLOAT);
}
else
{
retNode = gtNewBitCastNode(TYP_FLOAT, op1);
}
break;
}

case NI_System_BitConverter_Int64BitsToDouble:
{
GenTree* op1 = impStackTop().val;
assert(varTypeIsLong(op1));

if (op1->IsIntegralConst())
{
impPopStack();

int64_t i64Cns = op1->AsIntConCommon()->LngValue();
retNode = gtNewDconNode(*reinterpret_cast<double*>(&i64Cns));
}
#if TARGET_64BIT
else
{
// TODO-Cleanup: We should support this on 32-bit but it requires decomposition work
impPopStack();

retNode = gtNewBitCastNode(TYP_DOUBLE, op1);
}
#endif
break;
}

case NI_System_BitConverter_SingleToInt32Bits:
{
GenTree* op1 = impPopStack().val;
assert(varTypeIsFloating(op1));

if (op1->IsCnsFltOrDbl())
{
float f32Cns = (float)op1->AsDblCon()->gtDconVal;
retNode = gtNewIconNode(*reinterpret_cast<int32_t*>(&f32Cns));
}
else
{
if (op1->TypeGet() != TYP_FLOAT)
{
op1 = gtNewCastNode(TYP_FLOAT, op1, false, TYP_FLOAT);
}
retNode = gtNewBitCastNode(TYP_INT, op1);
}
break;
}

default:
break;
}
Expand Down Expand Up @@ -5518,6 +5608,53 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
result = NI_System_Activator_DefaultConstructorOf;
}
}
else if (strcmp(className, "BitConverter") == 0)
{
if (methodName[0] == 'D')
{
if (strcmp(methodName, "DoubleToInt64Bits") == 0)
{
result = NI_System_BitConverter_DoubleToInt64Bits;
}
else if (strcmp(methodName, "DoubleToUInt64Bits") == 0)
{
result = NI_System_BitConverter_DoubleToInt64Bits;
}
}
else if (methodName[0] == 'I')
{
if (strcmp(methodName, "Int32BitsToSingle") == 0)
{
result = NI_System_BitConverter_Int32BitsToSingle;
}
else if (strcmp(methodName, "Int64BitsToDouble") == 0)
{
result = NI_System_BitConverter_Int64BitsToDouble;
}
}
else if (methodName[0] == 'S')
{
if (strcmp(methodName, "SingleToInt32Bits") == 0)
{
result = NI_System_BitConverter_SingleToInt32Bits;
}
else if (strcmp(methodName, "SingleToUInt32Bits") == 0)
{
result = NI_System_BitConverter_SingleToInt32Bits;
}
}
else if (methodName[0] == 'U')
{
if (strcmp(methodName, "UInt32BitsToSingle") == 0)
{
result = NI_System_BitConverter_Int32BitsToSingle;
}
else if (strcmp(methodName, "UInt64BitsToDouble") == 0)
{
result = NI_System_BitConverter_Int64BitsToDouble;
}
}
}
else if (strcmp(className, "Math") == 0 || strcmp(className, "MathF") == 0)
{
if (strcmp(methodName, "Abs") == 0)
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/namedintrinsiclist.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ enum NamedIntrinsic : unsigned short

NI_System_Enum_HasFlag,

NI_System_BitConverter_DoubleToInt64Bits,
NI_System_BitConverter_Int32BitsToSingle,
NI_System_BitConverter_Int64BitsToDouble,
NI_System_BitConverter_SingleToInt32Bits,

NI_SYSTEM_MATH_START,
NI_System_Math_Abs,
NI_System_Math_Acos,
Expand Down
48 changes: 48 additions & 0 deletions src/coreclr/jit/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2232,6 +2232,38 @@ bool FloatingPointUtils::hasPreciseReciprocal(float x)
return mantissa == 0 && exponent != 0 && exponent != 127;
}

//------------------------------------------------------------------------
// isAllBitsSet: Determines whether the specified value is AllBitsSet
//
// Arguments:
// val - value to check for AllBitsSet
//
// Return Value:
// True if val is AllBitsSet
//

bool FloatingPointUtils::isAllBitsSet(float val)
{
UINT32 bits = *reinterpret_cast<UINT32*>(&val);
return bits == 0xFFFFFFFFU;
}

//------------------------------------------------------------------------
// isAllBitsSet: Determines whether the specified value is AllBitsSet
//
// Arguments:
// val - value to check for AllBitsSet
//
// Return Value:
// True if val is AllBitsSet
//

bool FloatingPointUtils::isAllBitsSet(double val)
{
UINT64 bits = *reinterpret_cast<UINT64*>(&val);
return bits == 0xFFFFFFFFFFFFFFFFULL;
}

//------------------------------------------------------------------------
// isNegative: Determines whether the specified value is negative
//
Expand Down Expand Up @@ -2310,6 +2342,22 @@ bool FloatingPointUtils::isNegativeZero(double val)
return bits == 0x8000000000000000ULL;
}

//------------------------------------------------------------------------
// isPositiveZero: Determines whether the specified value is positive zero (+0.0)
//
// Arguments:
// val - value to check for (+0.0)
//
// Return Value:
// True if val is (+0.0)
//

bool FloatingPointUtils::isPositiveZero(double val)
{
UINT64 bits = *reinterpret_cast<UINT64*>(&val);
return bits == 0x0000000000000000ULL;
}

//------------------------------------------------------------------------
// maximum: This matches the IEEE 754:2019 `maximum` function
// It propagates NaN inputs back to the caller and
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,10 @@ class FloatingPointUtils

static float infinite_float();

static bool isAllBitsSet(float val);

static bool isAllBitsSet(double val);

static bool isNegative(float val);

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

static bool isNegativeZero(double val);

static bool isPositiveZero(double val);

static double maximum(double val1, double val2);

static float maximum(float val1, float val2);
Expand Down
Loading