clang and bytecodePrimMultiply

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

clang and bytecodePrimMultiply

Eliot Miranda-2
 
Hi All,

    I'm trying to use clang in Xcode on Mac OS X to compile a new 32-bit VM.  One of my installations is Mavericks 10.9 with Xcode 6.2 and clang 6.0.  The other is 10.10.5 with Xcode 7.1 and clang 7.0.  Both seem to have problems with the integer side of bytecodePrimMultiply, the interpreter's multiplication routine:

        CASE(184)
            /* bytecodePrimMultiply */
            {
                sqInt arg;
                sqInt rcvr;
                sqInt result;
                char *sp;

                VM_LABEL(bytecodePrimMultiply);
                rcvr = longAtPointer(localSP + (1 * BytesPerOop));
                arg = longAtPointer(localSP + (0 * BytesPerOop));
                if (((rcvr & arg) & 1) != 0) { // both SmallIntegers?
                    rcvr = (rcvr >> 1); // convert from SmallInteger to value
                    arg = (arg >> 1);
                    result = rcvr * arg; // multiply
                    if ((arg == 0)
                     || (((result / arg) == rcvr) // check for overflow
                     && ((((sqInt)(result ^ (result << 1)))) >= 0))) { // check for SmallInteger overflow
                        /* begin internalPop:thenPush: */
                        longAtPointerput((localSP += (2 - 1) * BytesPerOop), ((result << 1) | 1));
                        /* begin fetchNextBytecode */
                        currentBytecode = byteAtPointer(++localIP);

                        goto l58;
                    }
                }
                else {

clang 6 inserts a spurious instruction at 0x36799:

0x36784: 89 ca movl %ecx, %edx // both SmallIntegers?
0x36786: 83 e2 01 andl $0x1, %edx
0x36789: 85 d0 testl %eax, %edx
0x3678b: 74 6b je 0x367f8
0x3678d: d1 f9 sarl %ecx // convert from SmallInteger to value
0x3678f: d1 f8 sarl %eax
0x36791: 0f af c8 imull %eax, %ecx // do the multiply
0x36794: 8d 14 09 leal (%ecx,%ecx), %edx
0x36797: 85 c0 testl %eax, %eax
0x36799: 89 f7 movl %esi, %edi // AFAICS, totally spurious
0x3679b: 74 08 je 0x367a5
0x3679d: 31 d1 xorl %edx, %ecx // check for SmallInteger overflow
0x3679f: 0f 88 96 01 00 00 js 0x3693b
0x367a5: 83 ca 01 orl $0x1, %edx

clang 7 does better:
0x36741: 89 ca movl   %ecx, %edx // both SmallIntegers?
0x36743: 83 e2 01 andl   $0x1, %edx
0x36746: 85 d0 testl  %eax, %edx
0x36748: 74 67 je     0x367b1
0x3674a: d1 f9 sarl   %ecx // convert from SmallInteger to value
0x3674c: d1 f8 sarl   %eax
0x3674e: 0f af c8 imull  %eax, %ecx // do the multiply
0x36751: 8d 14 09 leal   (%ecx,%ecx), %edx
0x36754: 85 c0 testl  %eax, %eax
0x36756: 74 08 je     0x36760
0x36758: 31 d1 xorl   %edx, %ecx // check for SmallInteger overflow
0x3675a: 0f 88 a9 01 00 00 js     0x36909
0x36760: 83 ca 01 orl    $0x1, %edx


What I don't understand is how, given

                typedef long sqInt;
                sqInt arg;
                sqInt rcvr;
                sqInt result;
...
                    result = rcvr * arg; // multiply

clang reasons it doesn't need to evaluate

                     || (((result / arg) == rcvr) // check for overflow

Given that arg and receiver can both have values > 64k, the result can of course overflow and there's no guarantee that because result = rcvr * arg, that (result / arg) == rcvr.

Am I missing something?  Are there flags I should be using?  This looks like a pretty basic issue.

_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: clang and bytecodePrimMultiply

Holger Freyther


> On 24 Nov 2015, at 20:44, Eliot Miranda <[hidden email]> wrote:
>
> Hi All,

Hi!


> Given that arg and receiver can both have values > 64k, the result can of course overflow and there's no guarantee that because result = rcvr * arg, that (result / arg) == rcvr.
>
> Am I missing something?  Are there flags I should be using?  This looks like a pretty basic issue.

I think you were already compiling with the -fwrapv option? Maybe it ignores it? I think the
blogpost from Nicolas Cellier[1] applies? I had a similar issue with GNU Smalltalk and clang
and I opted for using the GCC variant (that will be in newer clang releases too and we do not
have to think about the types) in the form of the __builtin_mul_overflow (the older variants are
either smul or smull and might be available in Apple's clang)[2]

i hope this helps
        holger



[1] http://smallissimo.blogspot.is/2015_04_01_archive.html
[2] http://clang.llvm.org/docs/LanguageExtensions.html
Reply | Threaded
Open this post in threaded view
|

Re: clang and bytecodePrimMultiply

johnmci
In reply to this post by Eliot Miranda-2
 

On Tue, Nov 24, 2015 at 11:44 AM, Eliot Miranda <[hidden email]> wrote:
 
Hi All,

    I'm trying to use clang in Xcode on Mac OS X to compile a new 32-bit VM.  One of my installations is Mavericks 10.9 with Xcode 6.2 and clang 6.0.  The other is 10.10.5 with Xcode 7.1 and clang 7.0.  Both seem to have problems with the integer side of bytecodePrimMultiply, the interpreter's multiplication routine:

        CASE(184)
            /* bytecodePrimMultiply */
            {
                sqInt arg;
                sqInt rcvr;
                sqInt result;
                char *sp;

                VM_LABEL(bytecodePrimMultiply);
                rcvr = longAtPointer(localSP + (1 * BytesPerOop));
                arg = longAtPointer(localSP + (0 * BytesPerOop));
                if (((rcvr & arg) & 1) != 0) { // both SmallIntegers?
                    rcvr = (rcvr >> 1); // convert from SmallInteger to value
                    arg = (arg >> 1);
                    result = rcvr * arg; // multiply
                    if ((arg == 0)
                     || (((result / arg) == rcvr) // check for overflow
                     && ((((sqInt)(result ^ (result << 1)))) >= 0))) { // check for SmallInteger overflow
                        /* begin internalPop:thenPush: */
                        longAtPointerput((localSP += (2 - 1) * BytesPerOop), ((result << 1) | 1));
                        /* begin fetchNextBytecode */
                        currentBytecode = byteAtPointer(++localIP);

                        goto l58;
                    }
                }
                else {

clang 6 inserts a spurious instruction at 0x36799:

0x36784: 89 ca movl %ecx, %edx // both SmallIntegers?
0x36786: 83 e2 01 andl $0x1, %edx
0x36789: 85 d0 testl %eax, %edx
0x3678b: 74 6b je 0x367f8
0x3678d: d1 f9 sarl %ecx // convert from SmallInteger to value
0x3678f: d1 f8 sarl %eax
0x36791: 0f af c8 imull %eax, %ecx // do the multiply
0x36794: 8d 14 09 leal (%ecx,%ecx), %edx
0x36797: 85 c0 testl %eax, %eax
0x36799: 89 f7 movl %esi, %edi // AFAICS, totally spurious
0x3679b: 74 08 je 0x367a5
0x3679d: 31 d1 xorl %edx, %ecx // check for SmallInteger overflow
0x3679f: 0f 88 96 01 00 00 js 0x3693b
0x367a5: 83 ca 01 orl $0x1, %edx

clang 7 does better:
0x36741: 89 ca movl   %ecx, %edx // both SmallIntegers?
0x36743: 83 e2 01 andl   $0x1, %edx
0x36746: 85 d0 testl  %eax, %edx
0x36748: 74 67 je     0x367b1
0x3674a: d1 f9 sarl   %ecx // convert from SmallInteger to value
0x3674c: d1 f8 sarl   %eax
0x3674e: 0f af c8 imull  %eax, %ecx // do the multiply
0x36751: 8d 14 09 leal   (%ecx,%ecx), %edx
0x36754: 85 c0 testl  %eax, %eax
0x36756: 74 08 je     0x36760
0x36758: 31 d1 xorl   %edx, %ecx // check for SmallInteger overflow
0x3675a: 0f 88 a9 01 00 00 js     0x36909
0x36760: 83 ca 01 orl    $0x1, %edx


What I don't understand is how, given

                typedef long sqInt;
                sqInt arg;
                sqInt rcvr;
                sqInt result;
...
                    result = rcvr * arg; // multiply

clang reasons it doesn't need to evaluate

                     || (((result / arg) == rcvr) // check for overflow

Given that arg and receiver can both have values > 64k, the result can of course overflow and there's no guarantee that because result = rcvr * arg, that (result / arg) == rcvr.

Am I missing something?  Are there flags I should be using?  This looks like a pretty basic issue.

_,,,^..^,,,_
best, Eliot




--
===========================================================================
John M. McIntosh. Corporate Smalltalk Consulting Ltd https://www.linkedin.com/in/smalltalk
===========================================================================
Reply | Threaded
Open this post in threaded view
|

Re: clang and bytecodePrimMultiply

Eliot Miranda-2
In reply to this post by Holger Freyther
 
Hi Holger,

On Tue, Nov 24, 2015 at 11:51 AM, Holger Freyther <[hidden email]> wrote:


> On 24 Nov 2015, at 20:44, Eliot Miranda <[hidden email]> wrote:
>
> Hi All,

Hi!


> Given that arg and receiver can both have values > 64k, the result can of course overflow and there's no guarantee that because result = rcvr * arg, that (result / arg) == rcvr.
>
> Am I missing something?  Are there flags I should be using?  This looks like a pretty basic issue.

I think you were already compiling with the -fwrapv option?

Thanks, that's what I was missing.  With -fwrapv the code is generated.

Maybe it ignores it? I think the
blogpost from Nicolas Cellier[1] applies? I had a similar issue with GNU Smalltalk and clang
and I opted for using the GCC variant (that will be in newer clang releases too and we do not
have to think about the types) in the form of the __builtin_mul_overflow (the older variants are
either smul or smull and might be available in Apple's clang)[2]

i hope this helps
        holger

indeed it does!
 
[1] http://smallissimo.blogspot.is/2015_04_01_archive.html
[2] http://clang.llvm.org/docs/LanguageExtensions.html



--
_,,,^..^,,,_
best, Eliot