Optimizer Behavior with a Comparison

A

Andrew Tomazos

Please consider the following code...

void on_equal_to();
void on_less_than();
void on_greater_than();

enum EComparisonResult
{
eEqualTo,
eLessThan,
eGreaterThan
};

inline EComparisonResult CompareIntegers(int a, int b)
{
if (a == b)
return eEqualTo;
else if (a < b)
return eLessThan;
else
return eGreaterThan;
}

void f1(int a, int b)
{
switch (CompareIntegers(a,b))
{
case eEqualTo: on_equal_to(); return;
case eLessThan: on_less_than(); return;
case eGreaterThan: on_greater_than(); return;
}
}

void f2(int a, int b)
{
if (a == b)
on_equal_to();
else if (a < b)
on_less_than();
else
on_greater_than();
}

Would you expect that the optimizer will produce code for f1 that has
equal performance to f2? Why or why not?

Thanks,
Andrew.
 
C

Carl

Andrew said:
Please consider the following code...

void on_equal_to();
void on_less_than();
void on_greater_than();

enum EComparisonResult
{
eEqualTo,
eLessThan,
eGreaterThan
};

inline EComparisonResult CompareIntegers(int a, int b)
{
if (a == b)
return eEqualTo;
else if (a < b)
return eLessThan;
else
return eGreaterThan;
}

void f1(int a, int b)
{
switch (CompareIntegers(a,b))
{
case eEqualTo: on_equal_to(); return;
case eLessThan: on_less_than(); return;
case eGreaterThan: on_greater_than(); return;
}
}

void f2(int a, int b)
{
if (a == b)
on_equal_to();
else if (a < b)
on_less_than();
else
on_greater_than();
}

Would you expect that the optimizer will produce code for f1 that has
equal performance to f2? Why or why not?

Thanks,
Andrew.


Depends on how smart your compiler is. You could simply try to run each
function a million times or so and clock it.
 
J

joecook

Please consider the following code...
Would you expect that the optimizer will produce code for f1 that has
equal performance to f2?  Why or why not?

Expect? Well, it's better to test than guess, but if I was forced to
make a bet, I would be rather confident that most decent compilers are
going to produce exactly equivalent code for each case. (Because in
this case, it does have all the information it needs to do two
compares, and then call a function). I have the most experience with
gcc, and I'm quite certain it's going to give you the same code either
way.

Joe Cook
 
E

Eric Sosman

Expect? Well, it's better to test than guess, but if I was forced to
make a bet, I would be rather confident that most decent compilers are
going to produce exactly equivalent code for each case. (Because in
this case, it does have all the information it needs to do two
compares, and then call a function). I have the most experience with
gcc, and I'm quite certain it's going to give you the same code either
way.

By "the same," I guess you mean "none?"

After correcting the syntax error, though, I confess
myself pleasantly surprised that gcc does indeed generate
the same code for both functions. Compilers seem to have
become a lot smarter while I was napping ...
 
A

Andrew Tomazos

I confess
myself pleasantly surprised that gcc does indeed generate
the same code for both functions.  Compilers seem to have
become a lot smarter while I was napping ...

Interesting. I assembled with the latest MSVC and /O2 and it produced
the below. It seems to have missed the connection, and failed to
fully unwind the switch in f1.
-Andrew.

$ cl.exe test.cpp /O2 /Fatest.asm
(Could it be that this command-line produces asm pre-optimizer? And/
or is there a relevant link-time optimizer as well?)

?f1@@YAXHH@Z PROC
mov eax, DWORD PTR _a$[esp-4]
mov ecx, DWORD PTR _b$[esp-4]
cmp eax, ecx
jne SHORT $LN11@f1
xor eax, eax
jmp SHORT $LN9@f1
$LN11@f1:
xor edx, edx
cmp eax, ecx
setge dl
inc edx
mov eax, edx
$LN9@f1:
sub eax, 0
je SHORT $LN3@f1
sub eax, 1
je SHORT $LN2@f1
sub eax, 1
jne SHORT $LN4@f1
jmp ?on_greater_than@@YAXXZ
$LN2@f1:
jmp ?on_less_than@@YAXXZ
$LN3@f1:
jmp ?on_equal_to@@YAXXZ
$LN4@f1:
ret 0

?f2@@YAXHH@Z PROC
mov eax, DWORD PTR _a$[esp-4]
mov ecx, DWORD PTR _b$[esp-4]
cmp eax, ecx
jne SHORT $LN8@f2
jmp ?on_equal_to@@YAXXZ
$LN8@f2:
jge SHORT $LN2@f2
jmp ?on_less_than@@YAXXZ
$LN2@f2:
jmp ?on_greater_than@@YAXXZ
?f2@@YAXHH@Z ENDP
 
G

Gene

I confess
myself pleasantly surprised that gcc does indeed generate
the same code for both functions.  Compilers seem to have
become a lot smarter while I was napping ...

Interesting.  I assembled with the latest MSVC and /O2 and it produced
the below.  It seems to have missed the connection, and failed to
fully unwind the switch in f1.
  -Andrew.

$ cl.exe test.cpp /O2 /Fatest.asm
(Could it be that this command-line produces asm pre-optimizer?  And/
or is there a relevant link-time optimizer as well?)

?f1@@YAXHH@Z PROC
        mov     eax, DWORD PTR _a$[esp-4]
        mov     ecx, DWORD PTR _b$[esp-4]
        cmp     eax, ecx
        jne     SHORT $LN11@f1
        xor     eax, eax
        jmp     SHORT $LN9@f1
$LN11@f1:
        xor     edx, edx
        cmp     eax, ecx
        setge   dl
        inc     edx
        mov     eax, edx
$LN9@f1:
        sub     eax, 0
        je      SHORT $LN3@f1
        sub     eax, 1
        je      SHORT $LN2@f1
        sub     eax, 1
        jne     SHORT $LN4@f1
        jmp     ?on_greater_than@@YAXXZ
$LN2@f1:
        jmp     ?on_less_than@@YAXXZ
$LN3@f1:
        jmp     ?on_equal_to@@YAXXZ
$LN4@f1:
        ret     0

?f2@@YAXHH@Z PROC
        mov     eax, DWORD PTR _a$[esp-4]
        mov     ecx, DWORD PTR _b$[esp-4]
        cmp     eax, ecx
        jne     SHORT $LN8@f2
        jmp     ?on_equal_to@@YAXXZ
$LN8@f2:
        jge     SHORT $LN2@f2
        jmp     ?on_less_than@@YAXXZ
$LN2@f2:
        jmp     ?on_greater_than@@YAXXZ
?f2@@YAXHH@Z ENDP

Gcc 4.1.3 for Intel gets it with gcc -O2 -S foo.c

....
_f2:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
cmpl %eax, 8(%ebp)
je L16
jl L17
popl %ebp
jmp _on_greater_than
.p2align 4,,7
L17:
popl %ebp
jmp _on_less_than
L16:
popl %ebp
jmp _on_equal_to
_f1:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
cmpl %eax, 8(%ebp)
je L19
jge L26
popl %ebp
jmp _on_less_than
L26:
popl %ebp
jmp _on_greater_than
L19:
popl %ebp
jmp _on_equal_to
 
J

joecook

     By "the same," I guess you mean "none?"

     After correcting the syntax error, though, I confess
myself pleasantly surprised that gcc does indeed generate
the same code for both functions.  Compilers seem to have
become a lot smarter while I was napping ...

I didn't notice the syntax error. I just tried cut and paste, and gcc
didn't notice any syntax error either.
joe cook
 
E

Eric Sosman

I didn't notice the syntax error. I just tried cut and paste, and gcc
didn't notice any syntax error either.

Hmmm. It's a syntax error in C; were you using C++?
Maybe this is Yet Another demonstration that the languages
are rather different, and of why answers obtained from two
forums can be in conflict and potentially confusing to the
questioner.
 
A

Andrew Tomazos

     Hmmm.  It's a syntax error in C; were you using C++?

The C-specific syntax error Eric is referring to is:

- inline EComparisonResult CompareIntegers(int a, int b)
+ inline enum EComparisonResult CompareIntegers(int a, int b)

-Andrew.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,160
Messages
2,570,890
Members
47,423
Latest member
henerygril

Latest Threads

Top