Hi all,
Today I noticed something strange with the way gcc optimises ternary
operations in c (and c++). Consider the following example where I call
foo(int) passing the clamped value of (s0, s1, s2):

/*----------------------------------------------------------------------------*/
#include <algorithm>

extern "C" {
void foo(int i);
}

void bar(int s0, int s1, int s2)
{
    foo(std::max(s0, std::min(s1, s2)));
}
/*----------------------------------------------------------------------------*/

When I compile the above class with -O1 -S, the generated assembly
contains 2 conditional moves and 0 branches:

stmfd sp!, {r3, lr}
.save {r3, lr}
cmp r2, r1
movge r2, r1
cmp r0, r2
movlt r0, r2
bl foo(PLT)
ldmfd sp!, {r3, pc}

If I replace the call to foo with one of the following:

foo(std::min(std::max(s0, s1), s2));
foo(s1 < s2 ? (s1 > s0 ? s1 : s0) : s2);
foo(s1 < s2 ? (s1 < s0 ? s0 : s1) : s2);
foo(s1 > s2 ? s2 : (s1 > s0 ? s1 : s0));
foo(s1 > s2 ? s2 : (s1 < s0 ? s0 : s1));

the generated output is the same. On the other side, when I replace
the foo call with one of the following:

foo(s0 < s1 ? (s2 < s1 ? s2 : s1) : s0);
foo(s0 < s1 ? (s2 > s1 ? s1 : s2) : s0);
foo(s0 > s1 ? s0 : (s2 < s1 ? s2 : s1));
foo(s0 > s1 ? s0 : (s2 > s1 ? s1 : s2));

The generated assembly contains 1 branch instruction + 2 conditional moves:

stmfd sp!, {r3, lr}
.save {r3, lr}
cmp r0, r1
bge .L2
cmp r1, r2
movlt r0, r1
movge r0, r2
.L2:
bl foo(PLT)
ldmfd sp!, {r3, pc}

I expected all the different combinations of "clamp" should generate
the same assembly.

Is there a reason for this? Is this a GCC "bug"?

Thanks
Andrea

Reply via email to