Intel x86 0x2E/0x3E Префикс Филиал Прогноз фактически используется?

В последнем пособии по разработке программного обеспечения Intel в нем описываются два префикса опкода:

Group 2 > Branch Hints

    0x2E: Branch Not Taken
    0x3E: Branch Taken

Они допускают явное предсказание ветвления инструкций перехода (коды операций вроде Jxx)

Я помню, как пару лет назад читал, что в x86 явное предсказание ветвей было по существу не-операцией в контексте внутренних предикаторных ветвей gccs.

Теперь я не понимаю, являются ли эти подсказки для ветвления x86 новой функцией или практически не работают на практике.

Кто-нибудь может это прояснить?

(То есть: генерируют ли функции предсказания ветвления gccs эти подсказки ветвей x86? - а текущие процессоры Intel не игнорируют их? - и когда это произошло?)

Update:

Я создал программу быстрого тестирования:

int main(int argc, char** argv)
{
    if (__builtin_expect(argc,0))
        return 1;

    if (__builtin_expect(argc == 2, 1))
        return 2;

    return 3;
}

Разберитесь со следующим:

00000000004004cc <main>:
  4004cc:   55                      push   %rbp
  4004cd:   48 89 e5                mov    %rsp,%rbp
  4004d0:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004d3:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  4004d7:   8b 45 fc                mov    -0x4(%rbp),%eax
  4004da:   48 98                   cltq   
  4004dc:   48 85 c0                test   %rax,%rax
  4004df:   74 07                   je     4004e8 <main+0x1c>
  4004e1:   b8 01 00 00 00          mov    $0x1,%eax
  4004e6:   eb 1b                   jmp    400503 <main+0x37>
  4004e8:   83 7d fc 02             cmpl   $0x2,-0x4(%rbp)
  4004ec:   0f 94 c0                sete   %al
  4004ef:   0f b6 c0                movzbl %al,%eax
  4004f2:   48 85 c0                test   %rax,%rax
  4004f5:   74 07                   je     4004fe <main+0x32>
  4004f7:   b8 02 00 00 00          mov    $0x2,%eax
  4004fc:   eb 05                   jmp    400503 <main+0x37>
  4004fe:   b8 03 00 00 00          mov    $0x3,%eax
  400503:   5d                      pop    %rbp
  400504:   c3                      retq   
  400505:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40050c:   00 00 00 
  40050f:   90                      nop

Я не вижу 2E или 3E? Может быть, gcc почему-то отказался от них?

Ответ 1

Эти префиксы команд не влияют на современные процессоры (что-то новое, чем Pentium 4). Они просто стоят один байт кодового пространства и, следовательно, не генерируют их, это правильно.

Подробнее см. руководства по оптимизации Agner Fog, в частности 3. Микроархитектура: http://www.agner.org/optimize/

"Справочное руководство по оптимизации архитектуры Intel® 64 и IA-32" больше не упоминает их в разделе об оптимизации ветвей (раздел 3.4.1): http://www.intel.de/content/dam/doc/manual/64-ia-32-architectures-optimization-manual.pdf

Эти префиксы представляют собой (безвредный) реликт архитектуры Netburst. В тотальной оптимизации вы можете использовать их для выравнивания кода, но все они хороши в настоящее время.

Ответ 2

gcc прав, чтобы не генерировать префикс, так как они не влияют на все процессоры с Pentium 4.

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

Ответ 3

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

Руководство по оптимизации Intel и Руководство Agner Fog ( которые уже упоминались здесь) оба имеют отличные описания этой функции.


Intel имеет это сказать о поколениях новее, чем Core 2:

Сделать код падения после условной ветки вероятной целью для ветки с прямой целью

Таким образом, условные ветки, которые перескакивают в коде, предсказаны не принятыми алгоритмом статического предсказания.

Это согласуется с тем, что GCC, похоже, сгенерировало с помощью __builtin_expect: код "ожидаемый" return 1/return 2 помещается в незанятые пути из условных ветвей, которые будут статически предсказаны как не -taken.

Дополнительно:

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

  • Предскажите безусловные ветки, которые нужно предпринять.

  • Предсказание косвенных ветвей НЕ приниматься.

Таким образом, в "ожидаемых" незанятых путях, где GCC помещал безусловный jmp в конец функции, эти скачки будут статически предсказаны как взятые (т.е. не пропущены).

Intel также говорит:

сделать провальный код, следующий за условной ветвью, маловероятной целью для ветки с обратной целью

Таким образом, предсказаны условные ветки, которые скачутся назад в коде, с помощью алгоритма статического предсказания.

Согласно Agner Fog, большинство Pentiums также следуют этому алгоритму:

В PPro, P2, P3, P4 и P4E прогнозируется, что команда передачи управления, которая не была замечена раньше или которая не находится в буфере целевого буфера, проваливается, если она идет вперед, и ее следует принимать, если он идет назад (например, петля). Статическое прогнозирование занимает больше времени, чем динамическое прогнозирование на этих процессорах.

Однако семейство Core 2 (и Pentium M) имеет совершенно другую политику:

Эти процессоры не используют статическое предсказание. Предиктор просто делает случайное предсказание при первом просмотре ветки, в зависимости от того, что происходит в записи BTB, назначенной новой ветке. Существует просто 50% -ный шанс сделать правильный прогноз прыжка или прыжка, но прогнозируемая цель верна.

Как и процессоры AMD, очевидно:

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

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

Ответ 4

Руководство разработчика программного обеспечения Intel® 64 и IA-32 → Том 2: Справочник по набору инструкций, AZ → Глава 2: Формат инструкции → 2.1 Формат инструкции для защищенного режима, режима реального адреса и режима виртуального 8086 → 2.1.1 Префиксы инструкций

Некоторые ранние микроархитектуры использовали их как отраслевые подсказки, но недавние поколений нет, и они зарезервированы для использования в будущем.