Почему нарушение «выходной зависимости» LZCNT имеет значение?
В то время, когда я сравнивал что-то, я измерил гораздо более низкую пропускную способность, чем я вычислил, и я сужусь до инструкции LZCNT (это также происходит с TZCNT), как показано в следующих тестах:
xor ecx, ecx _benchloop: lzcnt eax, edx add ecx, 1 jnz _benchloop
А также:
xor ecx, ecx _benchloop: xor eax, eax ; this shouldn't help, but it does lzcnt eax, edx add ecx, 1 jnz _benchloop
Вторая версия намного быстрее. Этого не должно быть. Нет причин, по которым LZCNT должен иметь входную зависимость от своего вывода. В отличие от BSR / BSF, инструкции xZCNT всегда перезаписывают свой вывод.
- Что такое 0x10 в инструкции по сборке «leal 0x10 (% ebx),% eax» x86?
- Windows 64-разрядный реестр против 32-разрядного реестра
- Что такое инструкции IN & OUT для x86?
- Распределение стека, отступы и выравнивание
- ошибка A2070: неверные операнды команд
Я запускаю это на 4770K, поэтому LZCNT и TZCNT не выполняются как BSR / BSF.
Что тут происходит?
- Почему целочисленное деление на -1 (отрицательное) приводит к FPE?
- Атомные операции, std :: atomic и упорядочение записи
- Сборка - JG / JNLE / JL / JNGE после CMP
- Какова цель инструкции «ПАУЗА» в x86?
- Разница между JA и JG в сборке
- Почему XCHG reg, reg 3 инструкции по микрооперации на современных архитектурах Intel?
- Какая технология сопоставления кеша используется в процессоре Intel Core i7?
- Что такое рамка стека в сборке?
Это просто ограничение в микро-архитектуре вашего процессора Intel Haswell и нескольких предыдущих 1 CPU. Он был исправлен для tzcnt
и lzcnt
как и для Skylake, но проблема остается для popcnt
.
На этих микроструктурах операнд назначения для tzcnt
, lzcnt
и popcnt
рассматривается как входная зависимость, хотя семантически это не так. Теперь я сомневаюсь, что это действительно «ошибка»: если бы это был просто надзор, я ожидал, что это будет исправлено в одной из нескольких новых микро-архитектур, выпущенных с момента ее появления.
Скорее всего, это компромисс дизайна, основанный на одном или обоих из следующих двух факторов:
-
Аппаратное обеспечение для
popcnt
,lzcnt
иtzcnt
, скорее всего, используется совместно с существующимиbsf
иbsr
. Теперьbsf
иbsr
действительно зависели от предыдущего значения назначения на практике 2 для особого случая ввода всех бит-ноль, поскольку в этом случае чипы Intel оставили цель немодифицированной. Поэтому вполне возможно, что простейшая конструкция комбинированного оборудования привела к тому, что другие аналогичные инструкции выполнялись в одном и том же подразделении, наследующем одну и ту же зависимость. -
Подавляющее большинство инструкций ALU из двух операндов x86 зависят от операнда-адресата, поскольку он также используется как источник. Три затронутые инструкции несколько уникальны тем, что они являются унарными операторами, но в отличие от существующих унарных операторов, таких как
not
иneg
которые имеют один операнд, используемый в качестве источника и адресата, у них есть разные операнды источника и адресата, что делает их поверхностно похожими на большинство 2- ввод инструкций. Возможно, схема переименования / планировщика просто не отличает особый случай этих унарных с двумя регистрами-операндами по сравнению с подавляющим большинством простых разделенных исходных / целевых инструкций с двумя входами, которые не имеют этой зависимости.
Фактически, для случая popcnt
Intel выпустила различные ошибки, охватывающие проблему ложной зависимости, такую как HSD146 для Haswell Desktop и SKL029 для Skylake , которая гласит:
Инструкция POPCNT может потребовать больше времени, чем ожидалось
Проблема Выполнение команды POPCNT с 32 или 64-битным операндом может быть отложено до тех пор, пока не будут выполнены предыдущие независимые инструкции.
Программное обеспечение Implication с использованием инструкции POPCNT может иметь более низкую производительность, чем ожидалось.
Обход проблемы Не определено
Я всегда считал этот необычный случай необычным, так как он не идентифицирует какой-либо функциональный дефект или несоответствие спецификации, которое имеет место, по существу, для всех других ошибок. Intel действительно не документирует конкретную модель производительности для механизма выполнения OoO, и на протяжении многих лет появилось и исчезло множество других «gotchas» производительности, многие из которых имеют гораздо больший эффект, что это очень незначительная проблема, t задокументировать в ошибках. Тем не менее, это, возможно, дает некоторые доказательства того, что это можно считать ошибкой. Как ни странно, erratum никогда не расширялся, чтобы включить tzcnt
или lzcnt
которые имели такую же проблему, когда они были введены.
1 Ну tzcnt
и lzcnt
появились только в Haswell, но проблема существует и для popcnt
которая была представлена в Nehalem, но проблема с ложной зависимостью, возможно, существует только для Sandy Bridge или позже.
2 На практике , хотя это не документировано в документах ISA, поскольку результат для ввода всех нhive не определен в руководствах Intel. Тем не менее, большинство или все чипы Intel реализовали поведение, так как оставляя регистр адресата неизменным в этом случае.
Вдоль линий того, что предложил @BrettHale, возможно (если нечетно), что вы попадаете в стойку с частичными флагами с коротким флагом. Состояние флага следует теоретически просто переименовать, потому что следующее добавление обновляет все флаги, но если это не по какой-то причине, то оно вводит зависимую от цикла зависимость, а вставка xor нарушит эту зависимость.
Трудно узнать наверняка, если это то, что происходит, но он выглядит случайным взглядом, чтобы быть наиболее вероятным объяснением; вы можете проверить гипотезу, заменив xor
на test
(который также нарушает зависимость флагов, но не влияет на зависимости регистра).