[Mono-devel-list] Mono.Math/BigInteger.cs patch - looks like a mcs bug instead - and found a HP oddity too.

Bernie Solomon bernard at ugsolutions.com
Thu Sep 4 01:58:01 EDT 2003


Well it wasn't quite as simple as I thought and took far too long to work
out what was
going on and I have found a couple of compiler bugs/oddities.

The first thing to note is that for this code:

using System;

class Test
{
    public static void Main()
    {
        int i = 1;
        int s = -16;
        i <<= s;
        Console.WriteLine(i);
    }

csc generates:

       IL_0000: ldc.i4.1
       IL_0001: stloc.0
       IL_0002: ldc.i4.s 0xfffffff0
       IL_0004: stloc.1
       IL_0005: ldloc.0
       IL_0006: ldloc.1
       IL_0007: ldc.i4.s 0x1f
       IL_0009: and
       IL_000a: shl

whereas mcs generates:

        IL_0000: ldc.i4.1
        IL_0001: stloc.0
        IL_0002: ldc.i4.s 0xfffffff0
        IL_0004: stloc.1
        IL_0005: ldloc.0
        IL_0006: ldloc.1
        IL_0007: shl

- note the missing & with 31. The shl spec for the CLR says:

      The return value is unspecified if shiftAmount is greater than or
equal to the width of value

Though the C# spec is more specific:
    If expr is an int or uint (32-bit quantity), the shift count is given by
the low-order five bits of count (count & 0x1f).

Though the CLR spec says nothing about -ve values for shift amounts one
might infer that the shift should be positive
however the C# spec is clear about anding with 0x1f.

Now as it happens the way the interpreter is coded (in my version and my
latest patch submission) for HP (compiled with
native 64 bits) the shift ends up as

    i <<= (long long) s;

in C where i is 'int'. What I then discovered is that this behaves
differently in the HP C compiler than

    i = i << (long long) s;

when s is outside the range 0 to 31. It behaves fine within range for both
expression. This is fine by the
C99 standard too as out of range shifts are undefined - though this was
mightly confusing in my initial C
test programs which didn't use <<= and behaved fine. Under 32 bit cygwin
both expressions are
equivalent and as it happens the & with 0x1f seems to be what happens anyway
(presumably this is
x86 spec).

After all that it seems to me that this is an mcs bug and it should insert
the 'and' instructions (the
JITter can take them out again if it knows x86, say, will do the right
thing). My patch to
BigInteger avoids the whole issue by keeping shifts within range (and my
initial reasoning
was LeftShift and RightShift are actually not quite consistent so I thought
one was wrong).

Whew... that was more than I expected to try and understand this.

Bernie Solomon
----- Original Message ----- 
From: "Sébastien Pouliot" <spouliot at videotron.ca>
To: "Bernie Solomon" <bernard at ugsolutions.com>
Cc: <mono-devel-list at lists.ximian.com>
Sent: Wednesday, September 03, 2003 6:17 PM
Subject: RE: [Mono-devel-list] Mono.Math/BigInteger.cs patch


> > These tests aren't run at all on Windows as they are in
> > corlib_plattest.dll.excludes (the
> > classes aren't in MS's corlib).
>
> Sorry I wasn't clear about "not showing up".
>




More information about the Mono-devel-list mailing list