HypnoToad
HypnoToad

Reputation: 605

Most efficient way to convert RGB to int?

I've encountered the following RGB-to-int method in various places:

//r,g, and b are bytes
int c = r;
c = (C << 8) | g;
c = (c << 8) | b;
return c;

But isn't it more efficient to say:

return (r << 16) | (g << 8) | r;

It seems like the first way results in a lot of unnecessary store/load instructions. Is there a reason everyone seems to prefer the first way over the second?

Upvotes: 0

Views: 2446

Answers (1)

olegarch
olegarch

Reputation: 3891

In the 2nd expression, you make small typo: twice used "r", and never "b". I assume, you meaning:

return (r << 16) | (g << 8) | b;

Regarding your question: result is very dependent on your computer architecture and compiler version. I build both versions with clang CC, FreeBSD OS, -O3. Source code:

int rgb1(int r, int g, int b) {
  int c = r;
  c = (c << 8) | g;
  c = (c << 8) | b;
  return c;
}

int rgb2(int r, int g, int b) {
    return (r << 16) | (g << 8) | b;
}

unsigned int rgb3(unsigned int r, unsigned int g, unsigned int b) {
    return (r * 256*256) + (g * 256) + b;
}

Assembly code following:

 rgb1:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        sall    $8, %eax
        orl     12(%ebp), %eax
        sall    $8, %eax
        orl     16(%ebp), %eax
        popl    %ebp
        ret
        .size   rgb1, .-rgb1
        .p2align 4,,15
.globl rgb2
        .type   rgb2, @function
rgb2:
        pushl   %ebp
        movl    %esp, %ebp
        movl    12(%ebp), %eax
        movl    8(%ebp), %edx
        sall    $8, %eax
        orl     16(%ebp), %eax
        popl    %ebp
        sall    $16, %edx
        orl     %edx, %eax
        ret
        .size   rgb2, .-rgb2
        .p2align 4,,15
.globl rgb3
        .type   rgb3, @function
rgb3:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        sall    $8, %eax
        addl    12(%ebp), %eax
        sall    $8, %eax
        addl    16(%ebp), %eax
        popl    %ebp
        ret

As you see, 1st function is 9 instructions, 2nd function is 10. Therefore, 1st seems little more efficient. But, in real life, it very depends on your compiler behavior. For example, rgb3() uses many math operations, but compiler optimized it to something, very close to rgb1().

Upvotes: 1

Related Questions