Может ли регистр хранить несколько значений одновременно? - PullRequest
1 голос
/ 12 апреля 2020

В случае 64-битного регистра x86, возможно ли одновременно хранить более одного значения в одном и том же регистре, если размер значения достаточно мал, чтобы в регистр могли поместиться несколько инструкций? Например, встраивание двух 32-битных целых в один регистр. Будет ли это плохо, если это возможно? Я читал о регистрах, и я совершенно новичок в этой концепции.

Ответы [ 2 ]

3 голосов
/ 12 апреля 2020

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


Да, это называется SIMD. (Одна инструкция, несколько данных) На x86-64 SSE2 (потоковые расширения SIMD) гарантированно доступны, поэтому у вас есть 16 различных 16-байтовых регистров (xmm0..15). И у вас есть инструкции, которые могут сделать упакованные FP добавить / sub / mul / div / sqrt / cmp из 4x 32-битных чисел с плавающей запятой, 2x 64-битных двойных, упакованных целых чисел add / sub / cmp / shift / et c для байта, Размеры операндов word, dword и qword.

(С некоторыми пробелами; SSE2 не очень ортогональн, например, самый узкий сдвиг - 16-битный, упакованный минимум / максимум доступен только для определенных размеров. Некоторые из этих пробелов заполнено SSE4.1).

И побитово-логические вещи, где ширина элемента не имеет значения (до AVX512 с регистрами маски ...)

См. https://www.felixcloutier.com/x86/. p... инструкции типа paddw упакованы целыми числами. ...ps и pd являются упакованными одинарными или упакованными двойными числами с плавающей запятой.

Компиляторы часто используют инструкции SSE / SSE2, такие как movdqa, чтобы обнулить или скопировать память в 16-байтовом фрагменты, а также для «векторизации» (используйте вычисления SIMD) для циклов над массивами. И G CC 7 или 8 и более поздние знают, как объединить нагрузки / хранилища соседних элементов структуры или элементов массива в скалярную загрузку или хранилище, например, с помощью RAX.

например, эта сумма массива:

int sumarr(const int *arr)
{
    int sum = 0;
    for(int i=0; i < 10240; i++) {
        sum += arr[i];
    }
    return sum;
}

компилируется следующим образом с GCC9.3 -O3 для x86-64 в проводнике компилятора Godbolt

sumarr:
        lea     rax, [rdi+40960]            # endp = arr + size
        pxor    xmm0, xmm0
.L2:                                        # do {
        movdqu  xmm2, XMMWORD PTR [rdi]        # v = arr[i + 0..3]
        add     rdi, 16                        # p += 4
        paddd   xmm0, xmm2                     # sum += v  // packed addition of 4 elements
        cmp     rax, rdi
        jne     .L2                         # }while(p != endp)
   ... then a horizontal vector sum ...
        MOVD eax, xmm0
        ret

Векторизация похожа на распараллеливание и для Подобное сокращение (суммирование массива до скалярного) требует ассоциативных операций. например, версия FP будет векторизоваться только с -ffast-math или с OpenMP.


В регистре общего назначения, таком как RAX, в котором нет инструкций для добавления SIMD без переноса между границами байтов (например, * 1042). *paddb xmm0, xmm1), он называется SWAR (SIMD в регистре).

Этот метод был более полезен в прошлом на ISA без надлежащего набора инструкций SIMD, таких как Alpha или MIPS64. Но это все еще возможно, и методы SWAR могут быть полезны как часть чего-то наподобие подсчета без инструкции popcnt, например, маскировка каждого второго бита и сдвиг, так что вы эффективно делаете 32 отдельных дополнения (которые не могут быть переполнены в каждом прочее) в 2-битные аккумуляторы.

Popcnt bithack, показанный в Как посчитать количество установленных бит в 32-битном целом числе? делает это, расширяясь до 4-битных счетчиков, затем 8-разрядный, затем используется умножение для сдвига и сложения на 4 различных сдвига и получения суммы в старшем байте.

2 голосов
/ 12 апреля 2020

Регистры не имеют тенденцию хранить инструкции, вместо этого они содержат данные для обработки инструкциями.

Однако, если вы хотели сохранить инструкции как данные, я полагаю (из здесь ) что самая длинная инструкция x86 составляет около пятнадцати байтов или 120 битов. Так что нет, он не помещается в один 64-битный регистр.

С точки зрения хранения нескольких значений данных в одном регистре, это, безусловно, возможно. Это даже поддерживается аппаратными средствами, причем даже самые ранние чипы x86 имеют ah и al, которые вместе образуют регистр ax.

Даже без этого вы, безусловно, можете вставлять / извлекать «подпрограмму». регистрирует "в / из регистров, используя побитовые операции (например, and, or, not и xor) и операции сдвига битов (например, shl, shr, rol, и ror).

...