"Оптимизация для 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 следующей, но давайте рассмотрим его: |
|
|