Может ли процессор выполнять операции памяти и арифметики одновременно? - PullRequest
0 голосов
/ 29 июня 2018

При изучении ассемблера и процессора меня уводит одна вещь, как делается инструкция :

add mem, 1

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

mov reg, mem
add reg, 1
mov mem, reg

Если я рассматриваю процессор с RISC Pipeline , мы можем наблюдать некоторые остановки. Это удивительно для такой простой инструкции, как i++:

|  Fetch  | Decode  | Exec    | Memory  | WriteB  |
          |  Fetch  |         |         | Decode  | Exec    | Memory  | WriteB  |
                    |  Fetch  |         |         |         | Decode  | Exec    | Memory  | WriteB  |

(Как я мог прочитать в книге Паттерсона Архитектура компьютера: количественный подход , регистры читаются в Декодировать uOp, Хранить / загружать в память uOp, и мы позволяем себе взять значение регистра в памяти uOp.)

Я прав? или у современных процессоров есть специальные методы, чтобы сделать это более эффективно?

1 Ответ

0 голосов
/ 29 июня 2018

Вы правы, современный x86 декодирует add dword [mem], 1 до 3 моп: загрузка, добавление ALU и хранилище.

Эти 3 зависимые операции не могут выполняться одновременно, поскольку более поздние должны ждать результата более ранней.

Но выполнение независимых инструкций может перекрываться, и современные процессоры очень настойчиво ищут и используют «параллелизм на уровне команд», чтобы запустить ваш код быстрее, чем 1 моп за такт. См. этот ответ для введения в то, что одно ядро ​​ЦП может делать параллельно , со ссылками на другие материалы, например, Руководство по микроархитектору x86 Агнера Фога , и описания Дэвида Кантера Песчаный мост и Бульдозер .


Но если вы посмотрите на семейства микроархитектур Intel P6 и Sandybridge, хранилище на самом деле представляет собой отдельный адрес магазина и данные хранилища . Uop-адрес хранилища не зависит от загрузки или ALU и может записать адрес хранилища в буфер хранилища в любое время. (Руководство по оптимизации Intel называет его буфером порядка памяти).

Для увеличения пропускной способности внешнего интерфейса, адреса хранения и данные хранилища могут декодироваться как пара с микроплавлением. Для add, так же как и для операции load + alu, процессор Intel может декодировать add dword [rdi], 1 в 2 мопа слитых доменов. (Та же самая нагрузка + добавление micro-fusion работает для декодирования add eax, [rdi] для одного мопа, поэтому его может декодировать любой из «простых» декодеров, а не только «сложный» декодер, который может обрабатывать многопользовательские инструкции. конец узких мест).

Именно поэтому add [mem], 1 более эффективен, чем inc [mem] на процессорах Intel, хотя inc reg столь же эффективен (но меньше), чем add reg,1. (inc не может микропереключить свою нагрузку + inc, что устанавливает флаги иначе, чем add). Инструкция INC против ADD 1: это имеет значение?

Но это только помогает внешнему интерфейсу быстрее вводить мопы в планировщик; нагрузка по-прежнему должна выполняться отдельно от надстройки.

Но нагрузка с микроплавлением не должна ждать, пока все остальные входные данные инструкции будут готовы. Рассмотрим инструкцию типа add [rdi], eax, где RDI и EAX являются входными данными для инструкции, но EAX не требуется, пока ALU не добавит uop. Загрузка может быть выполнена, как только загрузочный адрес будет готов, и есть свободный модуль выполнения загрузки (AGU + доступ к кешу). См. Также Как запланировано выполнение x86-мопов? .


регистры считываются в Decode uOp, Store / Load in Memory uOp, и мы позволяем себе взять значение регистра в Memory uOp

Все текущие микроархитектуры x86 используют неупорядоченное выполнение с переименованием регистров (алгоритм Томасуло). Инструкции переименовываются и выдаются в неработающую часть ядра (ROB и планировщик).

Физический регистровый файл не читается, пока инструкция не «отправлена» из планировщика в исполнительный модуль. (Или для недавно сгенерированных входных данных, переадресованных из других мопов.)


Независимые инструкции могут перекрывать свое выполнение . Например, процессор Skylake может поддерживать пропускную способность 4 мопов в слитых доменах / 7 неиспользуемых доменов за такт, включая 2 загрузки + 1 хранилище, в тщательно продуманном цикле :

.loop: ; HSW: 1.12c / iter. SKL: 1.0001c
    add edx, [rsp]           ; 1 fused-domain uop:  micro-fused load+add
    mov [rax], edi           : 1 fused-domain uop:  micro-fused store-address+store-data
    blsi ebx, [rdi]          : 1 fused-domain uop:  micro-fused load+bit-manip

    dec ecx
    jnz .loop                ; 1 fused-domain uop: macro-fused dec+branch runs on port 6

Процессоры семейства Sandybridge имеют L1d-кэш, способный на 2 чтения + 1 запись в такт. (До Haswell только 256-битные векторы могли работать с пределом пропускной способности AGU. См. Как кэширование может быть таким быстрым? .)

Пропускная способность фронт-энда семейства Sandybridge составляет 4 мопа слитых доменов за такт, и у них есть множество исполнительных блоков в бэк-энде для обработки различных комбинаций команд. (У Haswell и более поздних версий есть 4 целочисленных ALU, 2 порта загрузки, порт хранилища данных и выделенный AGU хранилища для простых режимов адресации хранилища. Таким образом, они часто могут быстро «догнать» после выполнения остановки кэша, что быстро комната в окне не в порядке, чтобы найти больше работы.)

...