Как BTS-адресат в памяти может быть значительно медленнее, чем загрузка / BTS reg,reg / store?

В общем случае, как может инструкция, которая может занимать память или регистрировать операнды, когда-либо быть медленнее с операндами памяти, чем mov + mov -> инструкция -> mov + mov

Основываясь на пропускной способности и задержке, найденных в таблицах инструкций Агнера Фога (в моем случае на Skylake, p238), я вижу, что следующие числа дляbtr/bts инструкции:

instruction, operands, uops fused domain, uops unfused domain, latency, throughput
mov          r,r       1                  1                    0-1      .25
mov          m,r       1                  2                    2        1
mov          r,m       1                  1                    2        .5
... 
bts/btr      r,r       1                  1                    N/A      .5
bts/btr      m,r       10                 10                   N/A      5

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

## hypothetical worst-case microcode that saves/restores a scratch register
mov m,r  // + 1  throughput , save a register
mov r,m  // + .5 throughput , load BTS destination operand
bts r,r  // + 1  throughput , do bts (or btr)
mov m,r  // + 1  throughput , store result
mov r,m  // + .5 throughput , restore register

В худшем случае у этого есть лучшая пропускная способность, чем просто bts m,r(4 < 5). (Примечание редактора: суммирование пропускной способности не работает, когда у них разные узкие места. Вам нужно учитывать операторы и порты; эта последовательность должна быть пропускной способностью 2c, узким местом при пропускной способности хранилища 1/ такт.)

Инструкции микрокода имеют собственный набор регистров, поэтому маловероятно, что это действительно понадобится. Кто-нибудь может объяснить почемуbts (или вообще любая инструкция) может иметь более высокую пропускную способность с памятью, регистровыми операндами, чем при использовании политики перемещения наихудшего случая.

(Примечание редактора: да, есть несколько скрытых временных регистров, которые может использовать микрокод. Что-то вроде add [mem], reg по крайней мере логически просто загружается в один из них, а затем сохраняет результат.)

1 ответ

Вам не хватает того, что BT, BTC, BTS и BTR не работают, как вы описали, когда используется операнд памяти. Вы предполагаете, что версии памяти работают так же, как версии регистров, но это не совсем так. В регистровой версии значение второго используемого операнда берется по модулю 64 (или 16, или 32). В версии для памяти значение второго операнда используется как есть. Это означает, что фактическая ячейка памяти, к которой обращается инструкция, может быть не адресом, заданным операндом памяти, а адресом где-то за ним.

Например, игнорируя необходимость сохранять регистры и атомарность, чтобы получить ту же операцию BTS [rsi + rdi], rax используя регистровую версию BTS, вам нужно будет сделать что-то вроде этого:

LEA rbx, [rsi + rdi]
MOV rcx, rax
SHR rcx, 8
MOV rdx, [rbx + rcx]
BTS rdx, rax
MOV [rbx + rcx], rdx

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

Другие вопросы по тегам