В общем, компилятор 1.1.772 генерирует неправильный IL код.
Попытался оформить ближе к тестам но поскольку я их не запускал (в смысле те что с компилятором), просто оформил по образу и подобию, но не факт что правильно.
Основная проблема в неверной конвертации uint32 в int64 в unchecked контексте.
Any comments?
using System;
using System.Console;
module Program
{
// At this moment all fine with this method.
CheckedUInt32ToInt64Conversion() : long
{
checked
{
def a : uint = 0xAA000000;
def b : uint = 0x00BB0000;
def c : uint = 0x0000CC00;
def d : uint = 0x000000DD;
def r = (a | b | c | d) :> long;
r
}
}
// UncheckedRound:
// Check generated IL code for this method:
//
// .locals init (
// [0] uint32 a,
// [1] uint32 b,
// [2] uint32 c,
// [3] uint32 d,
// [4] int64 r
// )
//
// def a : uint = 0xAA000000;
// IL: GOOD!
// > ldc.i4 -1442840576
// > stloc.0
//
// SECONDARY BUG:
// def b : uint = 0x00BB0000;
// IL: BAD!
// ldc.i4 12255232
// conv.ovf.u4 // hey! we are in unchecked! Using unwanted coversions it is bad.
// stloc.1
// ...same for def c and def d.
//
// PRIMARY BUG:
// def r = (a | b | c | d) :> long;
// IL:
// ldloc.0 //
// ldloc.1 //
// or //
// ldloc.2 //
// or //
// ldloc.3 //
// or // right
// conv.i8 // WRONG! This opcode now convert's signed int32 to signed int64 (i.e. with sign bit extension)
// but we need conversion unsigned int32 to signed int64
// while stack always stores signed values
// we just need use conv.u8 instead of conv.i8 (it always safe when convert uint32->int64, and same thing do C# compiler).
// btw, in checked mode nemerle generates conv.ovf.i8.un that looks fine, but redundant while this conversion type (conv.u8 enough)
// stloc.s r // good. (note that we store unsigned int64 as signed int64 but it is exact that we want in this case)
//
UncheckedUInt32ToInt64Conversion() : long
{
unchecked
{
def a : uint = 0xAA000000;
def b : uint = 0x00BB0000;
def c : uint = 0x0000CC00;
def d : uint = 0x000000DD;
def r = (a | b | c | d) :> long;
r
}
}
Main() : void
{
WriteLine("0x{0:X16}", CheckedUInt32ToInt64Conversion());
WriteLine("0x{0:X16}", UncheckedUInt32ToInt64Conversion());
}
}
/*
BEGIN-OUTPUT
0x00000000AABBCCDD
0x00000000AABBCCDD
END-OUTPUT
*/