Verifying the recommendation "Don't do the compilers job" from the book "The Ultimate Question of Programming, Refactoring, and Everything".
Note. The article was first published in Russian on livejournal.com. The article and is translation are posted on our website with the author's permission.
In the blog of PVS-Studio team you can find many examples of errors made by programmers and the recommendations of how you can avoid these mistakes (http://www.viva64.com/en/b/0391/).
The first piece of advice: don't do the compilers job. Do not optimize manually those fragments that will be optimized anyway. As an example we see a code fragment taken from MySQL project where a programmer deployed a loop manually and made a mistake. Further on, the author says if we write this function with a loop, the compiler will most likely deploy it itself.
Let's check it with the help of the online compiler. I copied the source code of function from the article and edited them a little bit so that they would compile without any additional files.
The compilation was done with the help of clang 3.9 compiler for the arm target with the optimization level -O2 (with these settings the compiler deploys the loops).
So, here is the original source code:
int rr_cmp(unsigned char *a, unsigned char *b)
{
if (a[0] != b[0])
return (int) a[0] - (int) b[0];
if (a[1] != b[1])
return (int) a[1] - (int) b[1];
if (a[2] != b[2])
return (int) a[2] - (int) b[2];
if (a[3] != b[3])
return (int) a[3] - (int) b[3];
if (a[4] != b[4])
return (int) a[4] - (int) b[4];
if (a[5] != b[5])
return (int) a[5] - (int) b[5];
if (a[6] != b[6])
return (int) a[6] - (int) b[6];
return (int) a[7] - (int) b[7];
}
The result for arm:
rr_cmp(unsigned char*, unsigned char*):
@ @rr_cmp(unsigned char*, unsigned char*)
ldrb r2, [r1]
ldrb r3, [r0]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #1]
ldrb r3, [r0, #1]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #2]
ldrb r3, [r0, #2]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #3]
ldrb r3, [r0, #3]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #4]
ldrb r3, [r0, #4]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #5]
ldrb r3, [r0, #5]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #6]
ldrb r3, [r0, #6]
cmp r3, r2
ldrbeq r1, [r1, #7]
ldrbeq r0, [r0, #7]
subeq r0, r0, r1
bxeq lr
.LBB0_7:
sub r0, r3, r2
bx lr
The source code, suggested by the author from PVS-Studio:
int rr_cmp(unsigned char *a,unsigned char *b)
{
for (int i = 0; i < 7; ++i)
{
if (a[i] != b[i])
return a[i] - b[i];
}
return a[7] - b[7];
}
Result:
rr_cmp(unsigned char*, unsigned char*):
@ @rr_cmp(unsigned char*, unsigned char*)
ldrb r2, [r1]
ldrb r3, [r0]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #1]
ldrb r3, [r0, #1]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #2]
ldrb r3, [r0, #2]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #3]
ldrb r3, [r0, #3]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #4]
ldrb r3, [r0, #4]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #5]
ldrb r3, [r0, #5]
cmp r3, r2
bne .LBB0_7
ldrb r2, [r1, #6]
ldrb r3, [r0, #6]
cmp r3, r2
ldrbeq r1, [r1, #7]
ldrbeq r0, [r0, #7]
subeq r0, r0, r1
bxeq lr
.LBB0_7:
sub r0, r3, r2
bx lr
Well... "Find 10 differences".
It's all the same.
However, oddly enough, the result for x86-64 will be slightly different. But this is another story.
0