@@ -476,6 +476,143 @@ public static string FloatToHex(float f)
476476 return returnValue ;
477477 }
478478
479+ [ TestMethod ]
480+ public void Cast_UIntToFloat ( )
481+ {
482+ // Regression test for https://github.com/nanoframework/Home/issues/1730
483+ // Conversion from a uint expression (I4 on stack) to float via conv.r.un + conv.r4
484+ // must produce the unsigned result even when no intermediate uint local is used.
485+
486+ ushort [ ] us = { 0x0000 , 0x8000 } ; // 0x80000000 = 2147483648u
487+
488+ float f1 = DecodeNumberToFloat1 ( us ) ; // direct cast of expression
489+ float f2 = DecodeNumberToFloat2 ( us ) ; // via uint local
490+
491+ Assert . AreEqual ( 2147483648f , f1 , "Direct cast of (uint expression) to float should be 2147483648, not -2147483648" ) ;
492+ Assert . AreEqual ( 2147483648f , f2 , "Indirect cast via uint local to float should be 2147483648" ) ;
493+ Assert . AreEqual ( f2 , f1 , "Direct and indirect uint-to-float conversions should produce equal results" ) ;
494+
495+ us = new ushort [ ] { 0xFFFF , 0xFFFF } ; // 0xFFFFFFFF = 4294967295u
496+ f1 = DecodeNumberToFloat1 ( us ) ;
497+ f2 = DecodeNumberToFloat2 ( us ) ;
498+ Assert . AreEqual ( f2 , f1 , "Direct and indirect uint-to-float should be equal for 0xFFFFFFFF" ) ;
499+
500+ us = new ushort [ ] { 0x1234 , 0x8765 } ; // 0x87651234, high bit set
501+ f1 = DecodeNumberToFloat1 ( us ) ;
502+ f2 = DecodeNumberToFloat2 ( us ) ;
503+ Assert . AreEqual ( f2 , f1 , "Direct and indirect uint-to-float should be equal for 0x87651234" ) ;
504+
505+ us = new ushort [ ] { 0xABCD , 0x1234 } ; // 0x1234ABCD, high bit clear
506+ f1 = DecodeNumberToFloat1 ( us ) ;
507+ f2 = DecodeNumberToFloat2 ( us ) ;
508+ Assert . AreEqual ( f2 , f1 , "Direct and indirect uint-to-float should be equal for 0x1234ABCD" ) ;
509+ }
510+
511+ [ TestMethod ]
512+ public void Cast_ULongToDouble ( )
513+ {
514+ // Regression test for https://github.com/nanoframework/Home/issues/1730
515+ // ulong arithmetic results land on the eval stack as I8 (signed).
516+ // conv.r.un must treat the I8 bits as unsigned; before the fix the
517+ // interpreter ignored the fUnsigned flag and produced a negative double.
518+
519+ uint [ ] ui = { 0x00000000 , 0x80000000 } ; // 0x8000000000000000 = 9223372036854775808uL
520+
521+ double d1 = DecodeULong1 ( ui ) ; // expression result (I8) → conv.r.un: was broken
522+ double d2 = DecodeULong2 ( ui ) ; // via ulong local (U8) → conv.r.un: was correct
523+
524+ Assert . AreEqual ( 9223372036854775808d , d1 , "Direct cast of (ulong expression) to double should be 9223372036854775808, not negative" ) ;
525+ Assert . AreEqual ( 9223372036854775808d , d2 , "Indirect cast via ulong local to double should be 9223372036854775808" ) ;
526+ Assert . AreEqual ( d2 , d1 , "Direct and indirect ulong-to-double conversions should produce equal results" ) ;
527+
528+ ui = new uint [ ] { 0xFFFFFFFF , 0xFFFFFFFF } ; // ulong.MaxValue = 18446744073709551615
529+ d1 = DecodeULong1 ( ui ) ;
530+ d2 = DecodeULong2 ( ui ) ;
531+ Assert . AreEqual ( 18446744073709551615d , d1 , "Direct cast of ulong.MaxValue expression to double should be 18446744073709551615" ) ;
532+ Assert . AreEqual ( d2 , d1 , "Direct and indirect ulong-to-double should be equal for ulong.MaxValue" ) ;
533+
534+ ui = new uint [ ] { 0x12345678 , 0x87654321 } ; // 0x8765432112345678, high bit set
535+ d1 = DecodeULong1 ( ui ) ;
536+ d2 = DecodeULong2 ( ui ) ;
537+ Assert . AreEqual ( d2 , d1 , "Direct and indirect ulong-to-double should be equal for 0x8765432112345678" ) ;
538+
539+ ui = new uint [ ] { 0x12345678 , 0x01234567 } ; // 0x0123456712345678, high bit clear
540+ d1 = DecodeULong1 ( ui ) ;
541+ d2 = DecodeULong2 ( ui ) ;
542+ Assert . AreEqual ( d2 , d1 , "Direct and indirect ulong-to-double should be equal for 0x0123456712345678" ) ;
543+ }
544+
545+ [ TestMethod ]
546+ public void Cast_ULongToFloat ( )
547+ {
548+ // Regression test for https://github.com/nanoframework/Home/issues/1730
549+ // Same sign-interpretation bug as Cast_ULongToDouble but for float (conv.r.un + conv.r4).
550+
551+ uint [ ] ui = { 0x00000000 , 0x80000000 } ; // 0x8000000000000000 = 9223372036854775808uL
552+
553+ float f1 = DecodeULong1Float ( ui ) ; // expression result (I8) → conv.r.un: was broken
554+ float f2 = DecodeULong2Float ( ui ) ; // via ulong local (U8) → conv.r.un: was correct
555+
556+ Assert . AreEqual ( 9223372036854775808f , f1 , "Direct cast of (ulong expression) to float should be 9223372036854775808, not negative" ) ;
557+ Assert . AreEqual ( 9223372036854775808f , f2 , "Indirect cast via ulong local to float should be 9223372036854775808" ) ;
558+ Assert . AreEqual ( f2 , f1 , "Direct and indirect ulong-to-float conversions should produce equal results" ) ;
559+
560+ ui = new uint [ ] { 0xFFFFFFFF , 0xFFFFFFFF } ; // ulong.MaxValue
561+ f1 = DecodeULong1Float ( ui ) ;
562+ f2 = DecodeULong2Float ( ui ) ;
563+ Assert . AreEqual ( f2 , f1 , "Direct and indirect ulong-to-float should be equal for ulong.MaxValue" ) ;
564+
565+ ui = new uint [ ] { 0x12345678 , 0x87654321 } ; // 0x8765432112345678, high bit set
566+ f1 = DecodeULong1Float ( ui ) ;
567+ f2 = DecodeULong2Float ( ui ) ;
568+ Assert . AreEqual ( f2 , f1 , "Direct and indirect ulong-to-float should be equal for 0x8765432112345678" ) ;
569+
570+ ui = new uint [ ] { 0x12345678 , 0x01234567 } ; // high bit clear
571+ f1 = DecodeULong1Float ( ui ) ;
572+ f2 = DecodeULong2Float ( ui ) ;
573+ Assert . AreEqual ( f2 , f1 , "Direct and indirect ulong-to-float should be equal for 0x0123456712345678" ) ;
574+ }
575+
576+ private static float DecodeNumberToFloat1 ( ushort [ ] us )
577+ {
578+ // Returns the uint expression directly as float, exercising conv.r.un on an I4 stack value.
579+ return ( ( uint ) us [ 1 ] << 16 ) + us [ 0 ] ;
580+ }
581+
582+ private static float DecodeNumberToFloat2 ( ushort [ ] us )
583+ {
584+ // Stores in a uint local first, so conv.r.un sees a correctly typed U4 local.
585+ uint u = ( ( uint ) us [ 1 ] << 16 ) + us [ 0 ] ;
586+ return u ;
587+ }
588+
589+ private static double DecodeULong1 ( uint [ ] ui )
590+ {
591+ // Returns the ulong expression directly as double.
592+ // conv.r.un is applied to an I8 arithmetic result on the eval stack,
593+ // which had a sign-interpretation bug before the fix.
594+ return ( ( ulong ) ui [ 1 ] << 32 ) | ui [ 0 ] ;
595+ }
596+
597+ private static double DecodeULong2 ( uint [ ] ui )
598+ {
599+ // Stores in a ulong local first, so conv.r.un sees a correctly typed U8 local.
600+ ulong u = ( ( ulong ) ui [ 1 ] << 32 ) | ui [ 0 ] ;
601+ return u ;
602+ }
603+
604+ private static float DecodeULong1Float ( uint [ ] ui )
605+ {
606+ // Returns the ulong expression directly as float (conv.r.un on I8, then conv.r4).
607+ return ( float ) ( ( ( ulong ) ui [ 1 ] << 32 ) | ui [ 0 ] ) ;
608+ }
609+
610+ private static float DecodeULong2Float ( uint [ ] ui )
611+ {
612+ // Stores in a ulong local first, so conv.r.un sees a correctly typed U8 local.
613+ ulong u = ( ( ulong ) ui [ 1 ] << 32 ) | ui [ 0 ] ;
614+ return ( float ) u ;
615+ }
479616
480617 #endregion
481618
0 commit comments