"Оптимизация для PENTIUM процессора" - читать интересную книгу автора

контролирующими цикл. Если мы установим что-нибудь между INC ECX и JNZ L1, то
это что-нибудь не должно влиять на флаг нуля (ZF). Инструкция
MOV [EDI+4*ECX], EBX после INC ECX создаст остановку AGI, таким образом нам
нужен более удачный код:

Пример 5:

MOV EAX, [N]
XOR ECX, ECX
SHL EAX, 2 ; 4 * N
JZ SHORT L3
MOV ESI, [A]
MOV EDI, [B]
SUB ECX, EAX ; - 4 * N
ADD ESI, EAX ; указатель на конец массива A
ADD EDI, EAX ; указатель на конец массива B
JMP SHORT L2
L1: MOV [EDI+ECX-4], EAX ; u
L2: MOV EAX, [ESI+ECX] ; v (спаривание)
XOR EAX, -1 ; u
ADD ECX, 4 ; v (спаривание)
INC EAX ; u
JNC L1 ; v (спаривание)
MOV [EDI+ECX-4], EAX
L3:

Здесь я использовал другой способ смены знака у EAX: инвертирование всех бит,
с последующим увеличением на 1. Причина, по которой я использовал этот метод
в том, что я могу использовать один грязный трюк инструкции INC: инструкция
INC не изменяет флаг переноса (CF), тогда как ADD изменяет. А используя ADD
вместо INC для увеличения счетчика моего цикла, я могу использовать как
признак окончания цикла флаг переноса (CF), а не флаг нуля (ZF). Таким образом
становиться возможным вставить INC EAX не меняя флага переноса. Вы можете
подумать, что можно бы было использовать LEA EAX, [EAX+1] вместо INC EAX,
которая тоже не изменить флаг, но инструкция LEA может вызвать остановку AGI,
так что это не лучший вариант.

Здесь я получил лучшее спаривание и теперь цикл исполняется за 3 такта. Хотите
ли вы увеличивать значение цикла на 1 (как в примере 4) или на 4 (как в
примере 5) - дело вкуса, для цикла это не принципиально.

Перекрытие операций
-------------------
Метод, используемый в примере 5 не очень удобный, потому что мы можем
использовать другие способы для улучшения спаривания. Один из способов
реорганизовать цикл - совместить конец одной операции с началом следующей. Я
буду называть это - свернутый цикл. Свернутый цикл оставляет незаконченную
операцию в каждой итерации, эта операция будет завершена в следующей итерации.
Например в примере 5 последний MOV одной итерации спаривается с первым MOV
следующей, но давайте рассмотрим его: