Об оптимизациях
Nov. 8th, 2016 10:31 amОригинал взят у
32bit_me в Об оптимизациях
В блоге PVS-Studio можно найти много примеров ошибок, совершаемых программистами, и много рекомендаций о том, как их избежать (http://www.viva64.com/ru/b/0391/).
Первый совет в этом документе: не берите на себя работу компилятора. Не оптимизируйте вручную то, что и так будет оптимизировано. В качестве примера приведён код из MySQL, в котором программист вручную развернул цикл, допустив при этом ошибку. Далее в статье написано, что если написать эту же функцию через цикл, то компилятор, скорее всего, её развернёт.
Давайте проверим это с помощью онлайн-компилятора. Я скопировал исходники функции из статьи, лишь немного подправив их так, чтобы они компилировались без дополнительных файлов.
Компиляция выполнялась компилятором clang 3.9 для таргета arm с уровнем оптимизации -O2 (при котором компилятор разворачивает циклы).
Итак, оригинальный исходник:
Результат для arm:
Исходник, предлагаемый автором из PVS:
Результат:
Как говорится, найдите 10 отличий.
Однако, для x86-64 результат будет несколько иной, как ни странно. Но это уже другая история.
Первый совет в этом документе: не берите на себя работу компилятора. Не оптимизируйте вручную то, что и так будет оптимизировано. В качестве примера приведён код из MySQL, в котором программист вручную развернул цикл, допустив при этом ошибку. Далее в статье написано, что если написать эту же функцию через цикл, то компилятор, скорее всего, её развернёт.
Давайте проверим это с помощью онлайн-компилятора. Я скопировал исходники функции из статьи, лишь немного подправив их так, чтобы они компилировались без дополнительных файлов.
Компиляция выполнялась компилятором clang 3.9 для таргета arm с уровнем оптимизации -O2 (при котором компилятор разворачивает циклы).
Итак, оригинальный исходник:
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]; }
Результат для 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Исходник, предлагаемый автором из PVS:
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]; }
Результат:
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Как говорится, найдите 10 отличий.
Однако, для x86-64 результат будет несколько иной, как ни странно. Но это уже другая история.