Можно с уверенностью предположить, что сборки x64 могут использовать TZCNT без проверки его поддержка через флаги процессора?
Подразумевает ли поддержка x64 поддержку BMI1?
Ответы (1)
Нет, конечно нет! x86-64 был новым в конце 2003 года (AMD K8) с только устаревшими инструкциями битового сканирования bsf
и bsr
и без остальных инструкций BMI1.
Первым процессором Intel с поддержкой BMI1 был Haswell в 2013 году. (Также представлен BMI2.)
Первым процессором AMD с поддержкой BMI1 был Piledriver в 2012 году.
AMD ABM (Advanced Bit Manipulation) в процессорах AMD K10 и более поздних версиях добавлены только popcnt
и lzcnt
, а не tzcnt
.
Википедия Наборы инструкций по обработке битов: поддержка процессоров. Обратите внимание, что процессоры Celeron/Pentium не декодируют префиксы VEX, поэтому у них отключены AVX и BMI1/BMI2, поскольку каждый из BMI1 и 2 включает некоторые инструкции, закодированные VEX, такие как andn
и blsr
. Это отстой; BMI1/2 наиболее полезен, когда компиляторы могут использовать его везде в исполняемом файле для более эффективных сдвигов числа переменных и глазков, поэтому по-прежнему продажа новых ЦП без BMI1/2 не приближает нас к возможности рассматривать их как базовый уровень, как мы делаем для P6 cmov
в 32-битном режиме.
Декодирование TZCNT на старых процессорах
Поскольку вы конкретно упомянули tzcnt
, его кодировка машинного кода - rep bsf
, поэтому старые процессоры будут выполнять его как BSF. Это дает тот же результат, что и tzcnt
, если ввод не равен нулю. т. е. tzcnt
работает на всех процессорах x86 (начиная с 386), когда ввод не равен нулю.
Но когда он равен нулю, tzcnt
выдаст размер операнда (например, 64), но < a href="https://www.felixcloutier.com/x86/bsf" rel="nofollow noreferrer">bsf
оставляет регистр назначения без изменений. tzcnt
устанавливает ФЛАГИ на основе результата, bsf
на основе ввода. AMD документирует поведение dst-unmodified в своем справочном руководстве по ISA. Intel только документирует это как неопределенное значение, но реализует то же поведение, что и AMD, по крайней мере, в существующих процессорах.
(Вот почему bsf
/bsr
имеют выходную зависимость от всех процессоров, например add
. К сожалению, tzcnt
/lzcnt
также имеют ложную зависимость от семейства Intel Sandybridge до Skylake: Почему нарушение выходной зависимости LZCNT имеет значение?. И почему popcnt
имеет значение в SnB-семействе before Cannon/Ice Lake, потому что он использует один и тот же исполнительный модуль.)
tzcnt
значительно быстрее на AMD, поэтому компиляторы, настраивающие общие процессоры или процессоры AMD, часто используют tzcnt
вместо bsf
без проверки функций процессора.
например для GNU C __builtin_ctz
. Эта встроенная функция имеет неопределенное поведение для ввода = 0, поэтому разрешено просто использовать bsf
без проверки на 0. И, следовательно, также разрешено использовать tzcnt
, потому что результат в этом случае ничем не гарантируется.
Почему TZCNT работает с моим процессором Sandy Bridge?
Для lzcnt
такого прямого/обратного сравнения не существует. Если его декодировать как rep bsr
с игнорированием бессмысленного префикса rep
, вы получите 31 - lzcnt(x)
, битовый индекс. https://fgiesen.wordpress.com/2013/10/18/bit-scanning-equivalencies/
Один из удобных приемов — ctz( x | 0x80000000 )
, потому что операция ИЛИ дешева1 и гарантирует, что bsf
всегда найдет ненулевой бит. Это не меняет результат для любых ненулевых x
, потому что это последний бит, на который будет смотреть bsf
. Этот трюк также работает для __builtin_clz(x|1)
/ bsr
, где это даже лучше, потому что or reg, imm8
еще короче, чем imm32
.
Сноска 1: or reg, imm32
работает для 32-битной константы; bts reg,63
на некоторых процессорах дешевле реализовать x|(1ULL<<63)
для 64-битного ввода.
tzcnt
без ошибок на предыдущих процессорах или видели компилятор, использующий его без-mbmi1
или-march=haswell
, и сомневались в других источниках, поэтому я подробно рассказал об этом в своем ответе. Но на первый взгляд, этот вопрос об ИМТ1 в целом, безусловно, может быть отклонен из-за отсутствия исследований. (Я думал об этом, но не стал.) - person Peter Cordes   schedule 25.04.2020bsf
для x86 (они все равно проверяют 0) и использовать tzcnt для сборок x64. Но не удалось найти четкую информацию, поддерживают ли его все процессоры x64 или нет. - person Pavel P   schedule 26.04.2020rep bsf
=tzcnt
безоговорочно (включая 32-битный режим), так что это быстрее на AMD, то же самое на Intel, за счет 1 байта инструкции. - person Peter Cordes   schedule 26.04.2020_tzcnt_u32
. Э-э, подождите, это в ifdef _MSC_VER, поэтому он никогда не используется с компиляторами, которые требуют включения-mbmi1
для_tzcnt_u32
. Так что да, они должны использовать_tzcnt_u32
. Мне любопытно, насколько это ужасно для MSVC, когдаx86_cpu_has_tzcnt
не является константой времени компиляции. - person Peter Cordes   schedule 26.04.2020x86_cpu_has_tzcnt
не является константой времени компиляции (если бы она была, компилятор, очевидно, удалил бы ее). Устанавливается во время выполнения, если процессор поддерживает BMI1. - person Pavel P   schedule 26.04.2020