Я предполагаю, что разработчики clang проверили, на каких уроках он был хорош, и обнаружили, что это только семейство SnB.
Звучит правильно, из-за прикольного ларька на семействе P6 и разных AMDДелители.
Использование флага в результате сдвига imm8 (не shift-by-implicit-1) в семействе P6 приводит к остановке внешнего интерфейса перед выдачей команды чтения флага, покасдвиг на пенсию .(Поскольку декодеры P6 не проверяют регистр imm8 = 0, чтобы оставить флаги неизмененными, в то время как SnB это делает). Инструкция INC против ADD 1: это имеет значение? .Возможно, именно поэтому clang не использует его для семейства P6.
Возможно, это другой способ проверки соответствующего состояния, которое не вызвало такой останов (например, test rcx,rcx
до je
, стоило бы того на Core2 / Nehalem). Но если бы разработчики clang не поняли причину, по которой это медленно на семействе P6, они бы не подумали, чтобы это исправить, и просто оставили это не выполненнымдля целей до SnB.(К сожалению, никто не добавил меня в обзор исправлений или список ошибок CC по этому поводу; это первый случай, когда clang проводит такую оптимизацию. Хотя я думаю, что мог бы упомянуть о смещении флагов смещения в комментариях к другому обзору LLVM илиВ любом случае, было бы забавно попробовать добавить test
и посмотреть, стоит ли это делать на Nehalem.)
Делители AMD имеют одинаковую производительность div в лучшем случае независимо от размера операнда,предположительно зависит только от фактической величины входов, согласно Agner Fog.Только наихудший случай растет с размером операнда. Так что я думаю безопасно запускать idiv r64
с небольшими входами, расширенными до 128/64-битных для AMD. (div / idiv на AMD - 2 моп для всех размеров операндов(кроме 8-битного, где он один, потому что он должен записывать только один выходной регистр: AH и AL = AX. В отличие от микрокодированного целочисленного деления Intel.)
Intel очень отличается: idiv r32
равен 9 мопам, тогда как idiv r64
составляет 59 мопов, при этом у Haswell пропускная способность в 3 раза хуже, чем у других членов семейства SnB.
Почему другиекомпиляторы, такие как GCC или ICC, делают это?
Возможно, потому что разработчики Clang подумали об этом, а gcc / icc их еще не скопировали. Если вы смотрели выступления Чандлера Каррута о perf
, одинНапример, он использовал игру с веткой, чтобы пропустить div
. Я предполагаю, что эта оптимизация была его идеей. Выглядит изящно.:)