Не уверен что вспомню где видел, сам к счастью не писал.
Про замену popcnt на 5 сдвигов и 5 and и 5 сложений (вычитаний) много где описано, в коде ещё 5 mov будут (все сдвиги одноадресные), порядка 20 команд. Не так страшно, что написали, примерно то и скомпилилось.
Сам попал лишь на комбинацию
mov EDX,1
.l: ;тут код вычисления следующего бита в C
rcl EDX,1
jnc .l
Очень удобный цикл вычисления (или получения откуда-то) битов, не нужен лишний регистр под счётчик.
На С мало того что нет бита C, так ещё и последние две команды ну никак совместно не реализуются. Сдвинуть можно, бит всунуть в младший можно, перейти по старшему можно, а вот сначала всунуть, а потом перейти - вах. Только лишняя переменная, или для счётчика циклов, или для старшего бита. На компе пофиг, в МК - когда как, бывает и жалко.
adc/sbb, ну вот как их на С закодировать? Единственный более-менее приемлемый способ без ввода расширенных типов данных - сравнивать результат сложения с операндом и если меньше, то писать в отдельную переменную перенос:
z=a+b+c; if(z<a || (c && z==a)) c=1; else c=0; (надеюсь не наврал, из головы же) - представляете во что это выльется в коде?
Как закодировать на C команду mul и тем более div с 128-битным результатом (аргументом) я даже думать не буду, не знаю. Все делают inline asm и не парятся.
pdep/pext вообще попадаем на цикл с 4 переменными (счётчик, результат, исходное число, маска) с условным переходом в нём и парой сдвигов (один условно). Даже не буду С код писать, и так понятно что команд 8-10 в асме и 32 итерации, мрак.
-- 21.01.2024, 23:39 --Кстати, вот выше в офтопе был выложен длиннющий код на C с функцией ValidateAuxData, проверяющей какие-то 64шт 16-битных полей. А при наличии AVX грузим всю структуру в 4 регистра, константу в 5-й регистр (а можно и в памяти оставить, на скорость не влияет), сравниваем командой vpcmpeqw, вываливаем старшие биты в РОН (vpmovmskb), там делаем and и если вдруг, то return. Без циклов. Фактически получается развёрнутый цикл на 4 итерации, но всё уложится команд в 20-25, причём времени займёт я бы так сказал тактов 12 в худшем случае. На 64 сравнения 16-битных полей! По 0.2 такта на поле. Скомпилите кто желает ту тучу циклов и посмотрите сколько будет и команд, и времени на них (тоже в худшем случае). Что будет короче или не сильно длиннее поверю, все циклы простые, что быстрее - нет, 0.2 такта на поле без векторизации никак не получить. А теперь вопрос: ну и какой компилятор додумается до такой векториазции?! Ну-ну. Можно и без AVX, грузить по 4 поля в регистр, xor, иногда and, jz, итого 3.3*16=53 с небольшим команд, думаю хватит тоже тактов 12. Додумается компилятор С до такого? Сомневаюсь.
Разумеется это полностью надуманный пример: товарища скорость С вполне устраивает и париться нет причин. Я и не предлагаю. Просто реальный пример "умности" компиляторов.