Skip to content

Commit 05fd573

Browse files
committed
Fix unsigned int to floating point number conversion
Simplest repro: Convert(Constant(uint.MaxValue), typeof(double)) Previously it would return -1, since the conv.r.un instruction wasn't used. It was only applied to uint->float, but not for double or any other integer type. Only uint/ulong was problematic, but the test covers all integer types. (nuint/nint are not supported by Linq.Expression conversions)
1 parent 7404512 commit 05fd573

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3508,10 +3508,12 @@ private static bool TryEmitPrimitiveValueConvert(Type sourceType, Type targetTyp
35083508
il.Demit(isChecked ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8);
35093509
break;
35103510
case TypeCode.Double:
3511+
if (sourceType.IsUnsigned())
3512+
il.Demit(OpCodes.Conv_R_Un);
35113513
il.Demit(OpCodes.Conv_R8);
35123514
break;
35133515
case TypeCode.Single:
3514-
if (sourceType == typeof(uint))
3516+
if (sourceType.IsUnsigned())
35153517
il.Demit(OpCodes.Conv_R_Un);
35163518
il.Demit(OpCodes.Conv_R4);
35173519
break;

test/FastExpressionCompiler.UnitTests/UnaryExpressionTests.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public int Run()
2828
ArrayLength_compiles();
2929
Convert_compiles();
3030
ConvertChecked_compiles();
31+
ConvertToFloat();
3132
Increment_Constant_compiles();
3233
Decrement_compiles();
3334
Increment_compiles();
@@ -52,7 +53,7 @@ public int Run()
5253
UnaryPlus_compiles();
5354
Unbox_compiles();
5455

55-
return 27;
56+
return 28;
5657
}
5758

5859

@@ -95,6 +96,33 @@ public void ConvertChecked_compiles()
9596
Asserts.AreEqual(1, result);
9697
}
9798

99+
public void ConvertToFloat()
100+
{
101+
var tests = new object[] {
102+
sbyte.MinValue, sbyte.MaxValue,
103+
short.MinValue, short.MaxValue,
104+
int.MinValue, int.MaxValue,
105+
long.MinValue, long.MaxValue,
106+
uint.MaxValue, uint.MaxValue - 1,
107+
ulong.MaxValue, ulong.MaxValue-10000,
108+
ushort.MaxValue, byte.MaxValue,
109+
char.MaxValue, 'a',
110+
true, false,
111+
double.MaxValue, float.MaxValue, (float)float.Epsilon,
112+
#if NET7_0_OR_GREATER
113+
Int128.MaxValue, Int128.MinValue, UInt128.MaxValue, // these use op_Explicit, but there isn't much coverage of that anyway
114+
#endif
115+
};
116+
foreach (var constant in tests)
117+
{
118+
var toFloat32 = Lambda<Func<float>>(Convert(Constant(constant), typeof(float)));
119+
var toFloat64 = Lambda<Func<double>>(Convert(Constant(constant), typeof(double)));
120+
121+
Asserts.AreEqual(toFloat32.CompileSys()(), toFloat32.CompileFast(true)(), $"(float){constant.ToCode()}");
122+
Asserts.AreEqual(toFloat64.CompileSys()(), toFloat64.CompileFast(true)(), $"(double){constant.ToCode()}");
123+
}
124+
}
125+
98126

99127
public void Increment_Constant_compiles()
100128
{

0 commit comments

Comments
 (0)