even or odd comparision optimization

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hey

Does the JIT perform this optimization?

old unoptimised even or odd test using modulo

if ((someVal % 2) == 0)
// even
else
// odd

optimized code

if ( (someVal & 1) == 0)
// even
else
// odd
 
I tried this code (v1.1.4322) and it seems like it does
not optimize (number % 2).


sealed class Test
{
static bool IsEven1(int number)
{
if ((number & 1) == 0)
{
return false;
}
else
{
return true;
}
}

static bool IsEven2(int number)
{
if ((number % 2) == 0)
{
return false;
}
else
{
return true;
}
}

static void Main()
{
IsEven1(1);
IsEven2(1);
System.Diagnostics.Debugger.Break();
IsEven1(1);
IsEven2(1);
}
}


The disassembly looks like:


static bool IsEven1(int number)
{
if ((number & 1) == 0)
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 push edi
00000007 push esi
00000008 mov edi,ecx
0000000a xor esi,esi
0000000c test edi,1
00000012 jne 00000018
return false;
00000014 xor esi,esi
00000016 jmp 0000001F
return true;
00000018 mov esi,1
0000001d jmp 0000001F
}


static bool IsEven2(int number)
{
if ((number % 2) == 0)
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 push edi
00000007 push esi
00000008 mov edi,ecx
0000000a xor esi,esi
0000000c mov eax,edi
0000000e and eax,80000001h
00000013 jns 0000001A
00000015 dec eax
00000016 or eax,0FFFFFFFEh
00000019 inc eax
0000001a test eax,eax
0000001c jne 00000022
return false;
0000001e xor esi,esi
00000020 jmp 00000029
return true;
00000022 mov esi,1
00000027 jmp 00000029
}
 
Did you try with cordbg with mode jit 1? If you got all the debugging
information, most likely it wasn't an optimized build with JIT optimizaions
on.

The code is actually completely optimized out by the JIT compiler. The only
thing in is a call to the debugger. Take that line out, and the whole
program gets optimized down to a ret.

-mike
MVP
 
Mike's remark is a valid one.

To look at the optimized code you have to create a release build
optimized for speed.

You then run the program and attach the debugger to the running
program. So e.g. read a character from the keyboard just before
the program stops. At that point the JIT has done its work and
you can look at the 80xx code.

Below the results I got on my machine.

public int OptimzeTest1(int i)
{
Thread.Sleep(60000);
if ((i % 2) == 0)
{
return i*2;
}
else
{
return i*3;
}
}

00000000 push esi
00000001 mov esi,edx
00000003 mov ecx,0EA60h
00000008 call dword ptr ds:[79B9C798h]
0000000e mov eax,esi <=========== if statement
00000010 and eax,80000001h
00000015 jns 0000001C
00000017 dec eax
00000018 or eax,0FFFFFFFEh
0000001b inc eax
0000001c test eax,eax
0000001e jne 00000026
00000020 add esi,esi
00000022 mov eax,esi
00000024 pop esi
00000025 ret
00000026 imul eax,esi,3
00000029 pop esi
0000002a ret

With
if ((i & 1) == 0)

the result is :

00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 push esi
00000007 mov dword ptr [ebp-4],ecx
0000000a mov esi,edx
0000000c mov ecx,0EA60h
00000011 call 72D6CC03
00000016 test esi,1 <==============
0000001c jne 00000027
0000001e mov eax,esi
00000020 add eax,eax
00000022 pop esi
00000023 mov esp,ebp
00000025 pop ebp
00000026 ret
00000027 imul eax,esi,3
0000002a pop esi
0000002b mov esp,ebp
0000002d pop ebp
0000002e ret
 
Was that with the sample code, as-posted? Using cordbg's dissassembly
feature, I just get the call to invoke the debugger and then a ret.

-mike
MVP

Tom Fransen said:
Mike's remark is a valid one.

To look at the optimized code you have to create a release build
optimized for speed.

You then run the program and attach the debugger to the running
program. So e.g. read a character from the keyboard just before
the program stops. At that point the JIT has done its work and
you can look at the 80xx code.

Below the results I got on my machine.

public int OptimzeTest1(int i)
{
Thread.Sleep(60000);
if ((i % 2) == 0)
{
return i*2;
}
else
{
return i*3;
}
}

00000000 push esi
00000001 mov esi,edx
00000003 mov ecx,0EA60h
00000008 call dword ptr ds:[79B9C798h]
0000000e mov eax,esi <=========== if statement
00000010 and eax,80000001h
00000015 jns 0000001C
00000017 dec eax
00000018 or eax,0FFFFFFFEh
0000001b inc eax
0000001c test eax,eax
0000001e jne 00000026
00000020 add esi,esi
00000022 mov eax,esi
00000024 pop esi
00000025 ret
00000026 imul eax,esi,3
00000029 pop esi
0000002a ret

With
if ((i & 1) == 0)

the result is :

00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 push esi
00000007 mov dword ptr [ebp-4],ecx
0000000a mov esi,edx
0000000c mov ecx,0EA60h
00000011 call 72D6CC03
00000016 test esi,1 <==============
0000001c jne 00000027
0000001e mov eax,esi
00000020 add eax,eax
00000022 pop esi
00000023 mov esp,ebp
00000025 pop ebp
00000026 ret
00000027 imul eax,esi,3
0000002a pop esi
0000002b mov esp,ebp
0000002d pop ebp
0000002e ret



"Michael Giagnocavo [MVP]" <[email protected]> wrote in message
Did you try with cordbg with mode jit 1? If you got all the debugging
information, most likely it wasn't an optimized build with JIT optimizaions
on.

The code is actually completely optimized out by the JIT compiler. The only
thing in is a call to the debugger. Take that line out, and the whole
program gets optimized down to a ret.

-mike
MVP
 
Hi Mike,

Tom confirmed your result. Then he went on to test a version that
wouldn't get optinised to dust - using a function which returns values.

Regards,
Fergus
 
Michael Giagnocavo said:
Was that with the sample code, as-posted? Using cordbg's dissassembly
feature, I just get the call to invoke the debugger and then a ret.

-mike
MVP

I used the VS debugger (attach to process).

The method I used returns some numbers to prevent the
code from getting optimizing 'to dust' as it was neatly put by Fergus.

I did not realy exam the assembly code further. I just
want to verify my description.

regards,
Tom
 
Yes, I just saw that I missed the CS source and only read the x86. duh. :S.
-mike
MVP
 
Back
Top