x86_64 - Сглобяване - условия на цикъл и неизправност

Аз не искам бенчмарк.

(Ако случаят беше такъв, щях да го направя сам.)


Въпросът ми:

Склонен съм да избягвам режимите на косвено/индексно адресиране за удобство.

Като заместител често използвам незабавно, абсолютно или регистърно адресиране.

Кодът:

; %esi has the array address. Say we iterate a doubleword (4bytes) array.
; %ecx is the array elements count
(0x98767) myloop:
    ... ;do whatever with %esi
    add $4, %esi
    dec %ecx
    jnz 0x98767;

Тук имаме сериализирано комбо (dec и jnz), което предотвратява правилното изпълнение извън реда (зависимост).

Има ли начин да се избегне това / да се прекъсне деп? (Не съм експерт по сглобяване).


person Kroma    schedule 02.08.2015    source източник
comment
Така че нека да ви кажа направо: искате условен скок, който зависи от резултата от предишната инструкция, да бъде изпълним извън реда с тази инструкция? Мисля, че това е логически невъзможно.   -  person davmac    schedule 02.08.2015
comment
Също така имайте предвид, че dec не се препоръчва, защото причинява спиране на актуализирането на частични флагове.   -  person Jester    schedule 02.08.2015
comment
@Jester: Тогава трябва да използвам суб?   -  person Kroma    schedule 02.08.2015
comment
@davmac: целта ми е да не завися от предишната инструкция   -  person Kroma    schedule 02.08.2015
comment
@Kroma имаш предвид, че искаш да поръчаш отново dec и add? В такъв случай можете ли да не използвате jcxz? (Не можете да направите условен скок, който не зависи от инструкцията, която създава условието).   -  person davmac    schedule 02.08.2015
comment
Можете да използвате lea 4(%esi),%esi за добавяне и това не засяга флаговете, така че можете да вмъкнете subl $1, %ecx по-нагоре. Както казва @davmac, не можете да се отървете от зависимостта, освен ако не използвате инструкцията loop, която отново не се препоръчва.   -  person Jester    schedule 02.08.2015
comment
@Jester: :) благодаря за съвета.   -  person Kroma    schedule 02.08.2015
comment
@davmac: да, не се чувствам длъжен да използвам условните скокове, ако има по-добро решение   -  person Kroma    schedule 02.08.2015
comment
Също така не забравяйте да развиете цикъла, ако е възможно, за да амортизирате разходите за режийните разходи за цикъла.   -  person Jester    schedule 02.08.2015
comment
@Jester: абсолютно, но дължината е променлива. Добър съвет обаче. Трябва да се грижи за дължината на реда на кеша.   -  person Kroma    schedule 02.08.2015
comment
@davmac: Не бих препоръчал jcxz, освен ако това не ви позволява да избегнете инструкция test или cmp. При процесорите на Intel това е инструкция 2-uop. (По-малко голяма работа, когато кодът е в uop кеша, в противен случай може да забави декодирането, защото може да се обработва само от комплексния декодер.)   -  person Peter Cordes    schedule 03.08.2015
comment
@jester: dec е добре, когато макро-слива със следния клон (на процесори на Intel.) Процесорите на AMD също така избягват задръствания с частични флагове, като третират отделни битове от флаговете като независими. (Въпреки това не съм сравнявал AMD или корпуса без сливане на макроси на Intel.)   -  person Peter Cordes    schedule 03.08.2015


Отговори (1)


Когато оптимизирате за процесори на Intel, винаги поставяйте инструкцията за задаване на флаг точно преди инструкцията за условно прескачане (ако е една от простите, изброени в таблицата по-долу), така че те да могат да се слеят макроси в една uop в декодерите.

Правенето на това не е значително по-лошо за по-стари процесори, които не извършват макросливане. Поставянето на настройката на флага по-рано може да съкрати наказанието за неправилно предвиждане на клона с едно за такива процесори, но изпълнението извън реда означава, че преместването на dec няколко инструкции по-рано няма да има реална разлика. Вижте също Избягвайте спирането на конвейера, като изчислявате условно рано. За да направите наистина разлика, вие правите неща като разгръщане на цикъла и/или разклоняване на нещо, което може да се изчисли по-просто, в идеалния случай без зависимост от бавен вход, така че OoO exec може да има разклонението вече разрешено, докато работи върху по-стари итерации на тялото на цикъла. т.е. деп-веригата на брояча на цикъла може да работи преди основната работа.

Нямам бенчмаркове, но не мисля, че малкият недостатък на все по-редките процесори оправдава пропускането на предимството на пропускателната способност на предния край (декодиране и проблем) за процесори, които правят синтез. Общата пропускателна способност на uop често може да бъде тясно място.

AMD Bulldozer/Piledriver/Steamroller може да слее test/cmp с който и да е jcc, но само test/cmp, не и други ALU инструкции. Така че определено се сравнява с клонове. Все още е ценно за процесорите на Intel да поставят други неща с разклонения, ако могат да се свържат с макро предпазител на sandybridge-family.

От ръководството за микроарки на Agner Fog, таблица 9.2 (за Sandybridge / Ivybridge):

First       | can pair with these  |  cannot pair with
instruction | (and the inverse)    |
---------------------------------------------
cmp         |jz, jc, jb, ja, jl, jg|   js, jp, jo
add, sub    |jz, jc, jb, ja, jl, jg|   js, jp, jo
adc, sbb    |none                  |
inc, dec    |jz, jl, jg            |   jc, jb, ja, js, jp, jo
test        | all                  |
and         | all                  |
or, xor, not, neg | none           |
shift, rotate     | none           |

Table 9.2. Instruction fusion

Така че основно inc/dec може да се слее макрос с jcc, стига условието да зависи само от битове, които са модифицирани от inc/dec.

(В противен случай те не се обединяват с макроси и получавате вмъкнат допълнителен uop за обединяване на флаговете (като когато четете eax след запис на al). Или при по-стари процесори частичните флагове спират.)

Core2 / Nehalem бяха по-ограничени по отношение на възможностите за макросливане (само за CMP/TEST с по-ограничени JCC комбинации), а Core2 изобщо не можеше да слее макроси в 64-битов режим.

Прочетете и ръководствата за оптимизиране на asm и C на Agner Fog, ако още не сте го направили. Те са пълни с основни знания.

person Peter Cordes    schedule 03.08.2015
comment
Благодаря много Питър, вече имах таблиците с инструкции и оптимизирам сглобяването от него. Последното обаче не го прочетох напълно (оттук и невежеството ми), НО ЩЕ го направя сега. Благодаря Петър :) - person Kroma; 03.08.2015
comment
@Kroma: Тази таблица е от microarchitecture.pdf. Забравих дали той споменава макросливане в ръководството за оптимизиране на asm, но вероятно поне го споменава. - person Peter Cordes; 03.08.2015
comment
Вероятно си струва да се спомене, че първата инструкция и втората инструкция трябва да бъдат в един и същ сегмент за декодиране от 16 байта, за да работи това (имат същия адрес, закръглен надолу до 16 байта). Мисля, че Агнер Фог споменава това някъде. - person Noah; 14.01.2021
comment
@Noah: първо, групите за декодиране не винаги са подравнени. Второ, Sandybridge-family се придържа към последната инструкция в група, ако е кандидат за синтез, в случай че първата инструкция в следващата група е разклонение. (Така че жертва известна пропускателна способност на наследеното декодиране, за да изгради може би по-компактни uop-кеш линии и може би да минимизира ROB пространството и потреблението на други бек-енд ресурси този път). Мисля, че това е обсъждано някъде в SO, но нищо конкретно не идва на ум. Все пак може да намериш нещо с Гугъл. - person Peter Cordes; 14.01.2021