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

Move checked math helpers to C# #102129

Merged
merged 3 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,22 @@
JITHELPER(CORINFO_HELP_LRSZ, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
#endif // TARGET_64BIT
JITHELPER(CORINFO_HELP_LMUL, JIT_LMul, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_LMUL_OVF, JIT_LMulOvf, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_ULMUL_OVF, JIT_ULMulOvf, CORINFO_HELP_SIG_16_STACK)
DYNAMICJITHELPER(CORINFO_HELP_LMUL_OVF, NULL, CORINFO_HELP_SIG_16_STACK)
DYNAMICJITHELPER(CORINFO_HELP_ULMUL_OVF, NULL, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_LDIV, JIT_LDiv, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_LMOD, JIT_LMod, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_ULDIV, JIT_ULDiv, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_ULMOD, JIT_ULMod, CORINFO_HELP_SIG_16_STACK)
JITHELPER(CORINFO_HELP_LNG2DBL, JIT_Lng2Dbl, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_ULNG2DBL, JIT_ULng2Dbl, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2INT, JIT_Dbl2Int, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2INT_OVF, JIT_Dbl2IntOvf, CORINFO_HELP_SIG_8_STACK)
DYNAMICJITHELPER(CORINFO_HELP_DBL2INT_OVF, NULL, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2LNG, JIT_Dbl2Lng, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2LNG_OVF, JIT_Dbl2LngOvf, CORINFO_HELP_SIG_8_STACK)
DYNAMICJITHELPER(CORINFO_HELP_DBL2LNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2UINT, JIT_Dbl2UInt, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2UINT_OVF, JIT_Dbl2UIntOvf, CORINFO_HELP_SIG_8_STACK)
DYNAMICJITHELPER(CORINFO_HELP_DBL2UINT_OVF, NULL, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2ULNG, JIT_Dbl2ULng, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBL2ULNG_OVF, JIT_Dbl2ULngOvf, CORINFO_HELP_SIG_8_STACK)
DYNAMICJITHELPER(CORINFO_HELP_DBL2ULNG_OVF, NULL, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_FLTREM, JIT_FltRem, CORINFO_HELP_SIG_8_STACK)
JITHELPER(CORINFO_HELP_DBLREM, JIT_DblRem, CORINFO_HELP_SIG_16_STACK)
DYNAMICJITHELPER(CORINFO_HELP_FLTROUND, NULL, CORINFO_HELP_SIG_8_STACK)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,195 +15,9 @@ namespace Internal.Runtime.CompilerHelpers
[StackTraceHidden]
internal static partial class MathHelpers
{
private const double Int32MaxValueOffset = (double)int.MaxValue + 1;
private const double UInt32MaxValueOffset = (double)uint.MaxValue + 1;

[RuntimeExport("Dbl2IntOvf")]
public static int Dbl2IntOvf(double value)
{
// Note that this expression also works properly for val = NaN case
if (value is > -Int32MaxValueOffset - 1 and < Int32MaxValueOffset)
{
return (int)value;
}

ThrowHelper.ThrowOverflowException();
return 0;
}

[RuntimeExport("Dbl2UIntOvf")]
public static uint Dbl2UIntOvf(double value)
{
// Note that this expression also works properly for val = NaN case
if (value is > -1.0 and < UInt32MaxValueOffset)
{
return (uint)value;
}

ThrowHelper.ThrowOverflowException();
return 0;
}

[RuntimeExport("Dbl2LngOvf")]
public static long Dbl2LngOvf(double value)
{
const double two63 = Int32MaxValueOffset * UInt32MaxValueOffset;

// Note that this expression also works properly for val = NaN case
// We need to compare with the very next double to two63. 0x402 is epsilon to get us there.
if (value is > -two63 - 0x402 and < two63)
{
return (long)value;
}

ThrowHelper.ThrowOverflowException();
return 0;
}

[RuntimeExport("Dbl2ULngOvf")]
public static ulong Dbl2ULngOvf(double value)
{
const double two64 = UInt32MaxValueOffset * UInt32MaxValueOffset;
// Note that this expression also works properly for val = NaN case
if (value is > -1.0 and < two64)
{
return (ulong)value;
}

ThrowHelper.ThrowOverflowException();
return 0;
}

#if !TARGET_64BIT
//
// 64-bit checked multiplication for 32-bit platforms
//

private const string RuntimeLibrary = "*";

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint High32Bits(ulong a)
{
return (uint)(a >> 32);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong BigMul(uint left, uint right)
{
return (ulong)left * right;
}

[RuntimeExport("LMulOvf")]
public static long LMulOvf(long left, long right)
{
#if DEBUG
long result = left * right;
#endif

// Remember the sign of the result
int sign = (int)(High32Bits((ulong)left) ^ High32Bits((ulong)right));

// Convert to unsigned multiplication
if (left < 0)
left = -left;
if (right < 0)
right = -right;

// Get the upper 32 bits of the numbers
uint val1High = High32Bits((ulong)left);
uint val2High = High32Bits((ulong)right);

ulong valMid;

if (val1High == 0)
{
// Compute the 'middle' bits of the long multiplication
valMid = BigMul(val2High, (uint)left);
}
else
{
if (val2High != 0)
goto Overflow;
// Compute the 'middle' bits of the long multiplication
valMid = BigMul(val1High, (uint)right);
}

// See if any bits after bit 32 are set
if (High32Bits(valMid) != 0)
goto Overflow;

long ret = (long)(BigMul((uint)left, (uint)right) + (valMid << 32));

// check for overflow
if (High32Bits((ulong)ret) < (uint)valMid)
goto Overflow;

if (sign >= 0)
{
// have we spilled into the sign bit?
if (ret < 0)
goto Overflow;
}
else
{
ret = -ret;
// have we spilled into the sign bit?
if (ret > 0)
goto Overflow;
}

#if DEBUG
Debug.Assert(ret == result, $"Multiply overflow got: {ret}, expected: {result}");
#endif
return ret;

Overflow:
ThrowHelper.ThrowOverflowException();
return 0;
}

[RuntimeExport("ULMulOvf")]
public static ulong ULMulOvf(ulong left, ulong right)
{
// Get the upper 32 bits of the numbers
uint val1High = High32Bits(left);
uint val2High = High32Bits(right);

ulong valMid;

if (val1High == 0)
{
if (val2High == 0)
return (ulong)(uint)left * (uint)right;
// Compute the 'middle' bits of the long multiplication
valMid = BigMul(val2High, (uint)left);
}
else
{
if (val2High != 0)
goto Overflow;
// Compute the 'middle' bits of the long multiplication
valMid = BigMul(val1High, (uint)right);
}

// See if any bits after bit 32 are set
if (High32Bits(valMid) != 0)
goto Overflow;

ulong ret = BigMul((uint)left, (uint)right) + (valMid << 32);

// check for overflow
if (High32Bits(ret) < (uint)valMid)
goto Overflow;

Debug.Assert(ret == left * right, $"Multiply overflow got: {ret}, expected: {left * right}");
return ret;

Overflow:
ThrowHelper.ThrowOverflowException();
return 0;
}

[LibraryImport(RuntimeLibrary)]
[SuppressGCTransition]
private static partial ulong RhpULMod(ulong dividend, ulong divisor);
Expand Down
20 changes: 14 additions & 6 deletions src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,16 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id,
break;

case ReadyToRunHelper.Dbl2IntOvf:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2IntOvf");
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ConvertToInt32Checked", null);
break;
case ReadyToRunHelper.Dbl2UIntOvf:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2UIntOvf");
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ConvertToUInt32Checked", null);
break;
case ReadyToRunHelper.Dbl2LngOvf:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2LngOvf");
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ConvertToInt64Checked", null);
break;
case ReadyToRunHelper.Dbl2ULngOvf:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "Dbl2ULngOvf");
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("ConvertToUInt64Checked", null);
break;

case ReadyToRunHelper.DblRem:
Expand All @@ -211,10 +211,18 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id,
mangledName = "RhpLMul";
break;
case ReadyToRunHelper.LMulOfv:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "LMulOvf");
{
TypeDesc t = context.GetWellKnownType(WellKnownType.Int64);
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("MultiplyChecked",
new MethodSignature(MethodSignatureFlags.Static, 0, t, [t, t]));
}
break;
case ReadyToRunHelper.ULMulOvf:
methodDesc = context.GetHelperEntryPoint("MathHelpers", "ULMulOvf");
{
TypeDesc t = context.GetWellKnownType(WellKnownType.UInt64);
methodDesc = context.SystemModule.GetKnownType("System", "Math").GetKnownMethod("MultiplyChecked",
new MethodSignature(MethodSignatureFlags.Static, 0, t, [t, t]));
}
break;

case ReadyToRunHelper.Mod:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,19 @@ private void ImportBinaryOperation(ILOpcode opcode)
}
}

private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned)
{
if (checkOverflow)
{
_dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2IntOvf), "_dbl2intovf");
_dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2UIntOvf), "_dbl2uintovf");
_dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2LngOvf), "_dbl2lngovf");
_dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Dbl2ULngOvf), "_dbl2ulngovf");

_dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf");
}
}

private void ImportFallthrough(BasicBlock next)
{
MarkBasicBlock(next);
Expand Down Expand Up @@ -1403,7 +1416,6 @@ private DefType GetWellKnownType(WellKnownType wellKnownType)
private static void ImportStoreIndirect(TypeDesc type) { }
private static void ImportShiftOperation(ILOpcode opcode) { }
private static void ImportCompareOperation(ILOpcode opcode) { }
private static void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) { }
private static void ImportUnaryOperation(ILOpcode opCode) { }
private static void ImportCpOpj(int token) { }
private static void ImportCkFinite() { }
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,14 @@ DEFINE_CLASS(UINT128, System, UInt128)

DEFINE_CLASS(MATH, System, Math)
DEFINE_METHOD(MATH, ROUND, Round, SM_Dbl_RetDbl)
#ifndef TARGET_64BIT
DEFINE_METHOD(MATH, MULTIPLY_CHECKED_INT64, MultiplyChecked, SM_Long_Long_RetLong)
DEFINE_METHOD(MATH, MULTIPLY_CHECKED_UINT64, MultiplyChecked, SM_ULong_ULong_RetULong)
#endif
DEFINE_METHOD(MATH, CONVERT_TO_INT32_CHECKED, ConvertToInt32Checked, NoSig)
DEFINE_METHOD(MATH, CONVERT_TO_UINT32_CHECKED, ConvertToUInt32Checked, NoSig)
DEFINE_METHOD(MATH, CONVERT_TO_INT64_CHECKED, ConvertToInt64Checked, NoSig)
DEFINE_METHOD(MATH, CONVERT_TO_UINT64_CHECKED, ConvertToUInt64Checked, NoSig)

DEFINE_CLASS(MATHF, System, MathF)
DEFINE_METHOD(MATHF, ROUND, Round, SM_Flt_RetFlt)
Expand Down
26 changes: 26 additions & 0 deletions src/coreclr/vm/ecall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,32 @@ void ECall::PopulateManagedHelpers()
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_BULK_WRITEBARRIER, pDest);

#ifndef TARGET_64BIT
pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__MULTIPLY_CHECKED_INT64));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_LMUL_OVF, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__MULTIPLY_CHECKED_UINT64));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_ULMUL_OVF, pDest);
#endif

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__CONVERT_TO_INT32_CHECKED));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_DBL2INT_OVF, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__CONVERT_TO_UINT32_CHECKED));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_DBL2UINT_OVF, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__CONVERT_TO_INT64_CHECKED));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_DBL2LNG_OVF, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__CONVERT_TO_UINT64_CHECKED));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_DBL2ULNG_OVF, pDest);

pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__MATH__ROUND));
pDest = pMD->GetMultiCallableAddrOfCode();
SetJitHelperFunction(CORINFO_HELP_DBLROUND, pDest);
Expand Down
Loading
Loading