Любая причина использования 32-битных целых чисел для общих операций с 64-битным процессором?

Интересно, стоит ли продолжать использовать int (который является 32-разрядным как для x86, так и для x86_64) для 64-битных программ для переменных, которые не имеют ничего особенного и на самом деле не должны охватывать до 2 ^ 64, как итерационные счетчики, или если лучше использовать size_t, который соответствует размеру слова процессора.

Конечно, если вы продолжаете использовать int, вы сохраняете половину памяти, и это может означать что-то, говорящее о кэше CPU, но я не знаю, если на 64-битной машине каждое 32-разрядное число должно быть расширено до 64 бит перед любым использованием.

EDIT: Я проверил некоторый тест с помощью моей программы (см. сам ответ, я все еще держу janneb как принято, хотя, потому что это хорошо). Оказывается, что есть значительное улучшение производительности.

Ответ 1

Для индексов массива и арифметики указателей типы, которые имеют такой же размер, как указатель (обычно size_t и ptrdiff_t), могут быть лучше, поскольку они избегают необходимости нуля или подписывать расширение регистра. Рассмотрим


float onei(float *a, int n)
{
  return a[n];
}

float oneu(float *a, unsigned n)
{
  return a[n];
}

float onep(float *a, ptrdiff_t n)
{
  return a[n];
}

float ones(float *a, size_t n)
{
  return a[n];
}

С GCC 4.4-O2 на x86_64 создается следующее asm:


    .p2align 4,,15
.globl onei
    .type   onei, @function
onei:
.LFB3:
    .cfi_startproc
    movslq  %esi,%rsi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE3:
    .size   onei, .-onei
    .p2align 4,,15
.globl oneu
    .type   oneu, @function
oneu:
.LFB4:
    .cfi_startproc
    mov %esi, %esi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE4:
    .size   oneu, .-oneu
    .p2align 4,,15
.globl onep
    .type   onep, @function
onep:
.LFB5:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE5:
    .size   onep, .-onep
    .p2align 4,,15
.globl ones
    .type   ones, @function
ones:
.LFB6:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE6:
    .size   ones, .-ones

Как видно, версии с индексом int и unsigned int (onei и oneu) требуют дополнительной команды (movslq/mov) для подписи/нулевого расширения регистра.

Как упоминалось в комментарии, недостатком является то, что кодирование 64-разрядного регистра занимает больше места, чем 32-битная часть, раздувая размер кода. Во-вторых, переменные ptrdiff_t/size_t требуют больше памяти, чем эквивалентный int; если у вас есть такие массивы, это, безусловно, может повлиять на производительность намного больше, чем относительно небольшое преимущество избежания расширения с нулевым/знаковым значком. Если неуверенный, профиль!

Ответ 2

В терминах Cache он экономит место; cache обрабатывает блоки данных, независимо от того, запрашивал ли процессор один адрес или полный фрагмент, равный размеру блока кэша.

Итак, если вы спрашиваете, занимают ли 32-разрядные номера 64-битные пространства внутри кешей на 64-битных машинах, тогда ответ будет отрицательным, они все равно возьмут 32 бита для себя. Таким образом, в общем случае это сэкономит вам некоторое пространство, особенно если вы используете большие массивы с частым доступом и т.д.

По моему личному мнению, простой int выглядит проще, чем size_t, и большинство редакторов не распознают тип size_t, поэтому подсветка синтаксиса также будет лучше, если вы используете int.;)

Ответ 3

Я немного кодирую модель твердых сфер. Источник можно найти на github.

Я пытался использовать size_t для переменных, которые используются как индекс массивов, и int, где я выполняю другие операции, не связанные с размером слова. Улучшение производительности было значительным: от 27 до 24 часов выполнения.

Ответ 4

Это должно быть решение разработчика компилятора.

int является естественным типом для "нормальных" знаковых целых чисел. Это до компилятора, чтобы решить, что это такое.
Если на конкретной платформе есть реальное преимущество в использовании 64-битных целых чисел, разработчик компилятора должен сделать int 64 бит. Стандарт позволяет это.

Если разработчик компилятора решил придерживаться 32-битных целых чисел, вы, как правило, должны доверять ему. Возможно, в некоторых редких случаях после значительных усилий по оптимизации вы обнаружите, что long работает лучше. Затем вы можете изменить.