2016-12-05 4 views
-2

Является ли бит сдвигом (по меньшей мере, 1 позиции) на коротком или байте быстрее (требуется меньше циклов процессора), чем сдвиг бит на целое (для архитектуры AMD64 или x86)? Я подозреваю, что ответ не из-за того, что в обоих случаях будет использоваться одна и та же 32-разрядная 64-разрядная команда процессора, и оба будут принимать одинаковое количество тактовых циклов. Это правда?Эффективность битового сдвига

+3

Что скажут тесты на вашем оборудовании? Какой машинный код испускается для ваших случаев использования? – tadman

+0

Лучшая ставка здесь - сравнить пример, который правильно отражает вашу проблему. Есть много проблем, не связанных с циклами, потребляемыми одной инструкцией, которая может ускорить или замедлить вашу программу (загрузка/хранение, simd и т. Д.). –

+0

*** Является ли сдвиг бит (не менее 1 позиции) коротким или байтом быстрее (требуется меньше циклов процессора), чем сдвиг бит на целое число (для архитектуры AMD64 или x86)? *** № – drescherjm

ответ

2

Это зависит. Вообще говоря, если у вас есть N-разрядный процессор, то, скорее всего, все до N бит будут перемещаться в одно и то же время, большие переменные занимают больше времени. Если вы выполняете операции над байтами, но хотите, чтобы вы использовали целочисленное число подходящего размера для скорости, используйте тип .

Но: если вы выполняете смещение битов в цикле, тогда компилятор может иметь возможность векторизовать ваш код. Если у вас есть процессор с инструкциями SSE2, он может выполнять 8 16-разрядных сдвигов в одной инструкции. Если у вас есть AVX или даже AVX512, он может сделать 16 или даже 32 16-битных сдвига в одной инструкции. Однако, эффективнее, чем использование регулярных инструкций, зависит от того, насколько легко загружать многие переменные в регистры SSE, и если вы выполняете больше операций, чем просто сдвиги бит на них.

Поучительно посмотреть на выход ассемблера из компилятора (например, использовать gcc -save-temps для компиляции вашей программы и посмотреть полученный файл .s). Обратите внимание, что выбранный уровень оптимизации оказывает очень большое влияние на сгенерированный ассемблер.

Лучший способ определить, какой самый быстрый переменный размер - это просто его измерить.

1

Код, который был опубликован ранее, был неправильным. Хотя код содержал сдвиг, поскольку результат не был сохранен, компилятор просто пропустил его. Вот простой ИНТ пример:

void main() { 
    int value = 0; 
    value = value << 3; 
} 

Краткое пример:

void foo() { 
    short value = 0; 
    value = value << 3; 
} 

Integer пример генерирует:

.file "main.c" 
    .text 
    .globl _Z3foov 
    .def _Z3foov; .scl 2; .type 32; .endef 
    .seh_proc _Z3foov 
_Z3foov: 
.LFB0: 
    pushq %rbp 
    .seh_pushreg %rbp 
    movq %rsp, %rbp 
    .seh_setframe %rbp, 0 
    subq $16, %rsp 
    .seh_stackalloc 16 
    .seh_endprologue 
    movl $0, -4(%rbp) 
    sall $3, -4(%rbp) 
    nop 
    addq $16, %rsp 
    popq %rbp 
    ret 
    .seh_endproc 
    .ident "GCC: (GNU) 5.4.0" 

Короткий пример генерирует:

.file "main.c" 
    .text 
    .globl _Z3foov 
    .def _Z3foov; .scl 2; .type 32; .endef 
    .seh_proc _Z3foov 
_Z3foov: 
.LFB0: 
    pushq %rbp 
    .seh_pushreg %rbp 
    movq %rsp, %rbp 
    .seh_setframe %rbp, 0 
    subq $16, %rsp 
    .seh_stackalloc 16 
    .seh_endprologue 
    movw $0, -2(%rbp) 
    movswl -2(%rbp), %eax 
    sall $3, %eax 
    movw %ax, -2(%rbp) 
    nop 
    addq $16, %rsp 
    popq %rbp 
    ret 
    .seh_endproc 
    .ident "GCC: (GNU) 5.4.0" 

Короткий пример выполняет:

movw $0, -2(%rbp) 
movswl -2(%rbp), %eax 
sall $3, %eax 
movw %ax, -2(%rbp) 

Integer пример выполняет:

movl $0, -4(%rbp) 
sall $3, -4(%rbp) 

Так это выглядит, как без какой-либо оптимизации компилятора, целочисленный сдвиг на самом деле быстрее.

+0

Как насчет других процессоров, таких как серия ARM? –

+1

Чувак, никакой сдвиг даже не выполняется ни в одной из этих функций, они оба просто сохраняют ноль в локальной переменной, с двумя различными смещениями кадра для двух разных размеров. –

+0

Ответ на этот вопрос (если вы действительно сдвигаете этот пример), будет занимать 1 такт (или меньше), чтобы сделать shft, если нет стойки конвейера на современном процессоре x86. – drescherjm

1

Моя гипотеза заключается в том, что сдвиги в 8-битных или 16-разрядных (без знака) целых числах такие же, как сдвиги бит в 32-битных количествах на 32-разрядных машинах слов.

Большинство 32-разрядных процессоров размера слова работают внутри 32-битных величин. Переключатель ствола, арифметический блок и т. Д. Предназначены для 32-разрядных операций. Механизм выборки данных преобразует 8-битное или 16-битное количество в 32-битное количество до того, как произойдет операция сдвига. 32-битное количество не требует каких-либо корректировок, поэтому может быть небольшая задержка с целыми числами меньшего размера.

С другой стороны, могут быть процессоры, имеющие специальные пути данных для 8-битных или 16-разрядных целых чисел.

Способ проверки - это профиль в вашей системе и других целевых системах.

Кроме того, спросите себя, важна или значительна разница во времени выполнения.

Смежные вопросы