Оптимизация для процессоров семейства Pentium: 10. Спаривание целочисленных инструкций (PPlain и PMMX) — Архив WASM.RU

Все статьи

Оптимизация для процессоров семейства Pentium: 10. Спаривание целочисленных инструкций (PPlain и PMMX) — Архив WASM.RU

10.1 Совершенное спаривание

У PPlain и PMMX есть два конвеера, выполняющих инструкции, которые называются U-конвеер и V-конвеер. В определенных условий можно выполнить две инструкции одновременно, одну в U-конвеере, а другую в V-конвеере. Это практически удваивает скорость. Поэтому имеет смысл перегруппировать ваши инструкции и сделать их спариваемыми.

Следующие инструкции могут находится в любом конвеере.

  • MOV регистр, память или уже заданного числа в регистр или память
  • PUSH регистр или число, POP регистр
  • LEA, NOP
  • INC, DEC, ADD, SUB, CMP, AND, OR, XOR,
  • и некоторые разновидности TEST (смотри главу 26.14)

Следующие инструкции спариваемы только в U-конвеере:

  • ADC, SBB
  • SHR, SAR, SHL, SAL с число в качестве аргумента
  • ROR, ROL, RCR, RCL с единицей в качестве аргумента
Следующие инструкции спариваемы только в V-конвеере:
  • ближний вызовой
  • короткий и ближний переход
  • короткий и ближний условный переход

Все другие целочисленные инструкции могут выполняться только в U-конвеере и не могут спариваться.

Две следующие друг за другом инструкции будут спариваться, если соблюденые следующие условия:

  • Первая инструкция спариваема в U-конвеере, а вторая - в V-конвеере.
  • Вторая инструкция не читает и не пишет из регистра, если пишет первая инструкция.

Примеры:

    MOV EAX, EBX / MOV ECX, EAX     ; чтение после записи, не спаривается
    MOV EAX, 1   / MOV EAX, 2       ; запись после записи, не спаривается
    MOV EBX, EAX / MOV EAX, 2       ; запись после чтения, спаривается
    MOV EBX, EAX / MOV ECX, EAX     ; чтение после чтения, спаривается
    MOV EBX, EAX / INC EAX          ; чтение и запись после чтения, спаривается

3. Неполные регистры считаются полными регистрами.

Пример:

    MOV AL, BL  /  MOV AH, 0

пишут в разные части одного и того же регистра, не спаривается.

4. Две инструкции, пишущие в разные части регистра флагов могут спариваться не смотря на правила 2 и 3.

Пример:

    SHR EAX, 4 / INC EBX            ; спаривается

5. Инструкция, которая пишет в регистр флагов может спариваться с условным переходом несмотря на правило 2.

Пример:

    CMP EAX, 2 / JA LabelBigger     ; спаривается

6. Следующая комбинация инструкций может спариваться несмотря на тот факт, что обе изменяют указатель на стек:

    PUSH + PUSH,  PUSH + CALL,  POP + POP

7. Есть ограничения на спаривание инструкций с префиксами. Есть несколько типов префиксов:

  • у инструкций, обращающихся к сегменту, не являющемся сегментом по умолчанию, есть сегментный префикс.
  • у инструкций, использующих 16-ти битные данные в 32-ом режиме или 32-х битные данные в 16-битном режиме, есть префикс размера операнда.
  • у инструкций, использующих 32-х битную адресацию через регистры в 16-ти битном режиме, есть префикс размера адреса.
  • у повторяющихся есть префикс повторения.
  • у закрытых инструкций есть префикс LOCK.
  • у многих инструкций, которых не было на процессоре 8086 есть двухбайтный опкод, чей первый байт равен 0FH. Байт 0FH считается префиксом только на PPlain. Наиболее часто используемые инструкции с этим префиксом следующие: MOVZX, MOVSX, PUSH FS, POP FS, PUSH GS, POP GS, LFS, LGS, LSS, SETcc, BT, BTC, BTR, BTS, BSF, BSR, SHLD, SHRD, и IMUL с двумя операндами и без числового операнда.

На PPlain инструкция с префиксом может выполняться только в U-конвеере, кроме ближних условных переходов.

На PMMX инструкции с префиксами размера операнда, размера адреса или 0FH могут выполняться в любом конвеере, в то время как инструкции с префиксами сегмента, повторения или LOCK могут выполняться только в U-конвеере.

8. Инструкция, в которой используется одновременно адресация со смещение и числовые данные на PPlain не спариваются, на PMMX могут спариваться только в U-конвеере:

    MOV DWORD PTR DS:[1000], 0    ; не спаривается или только в U-конвеере
    CMP BYTE PTR [EBX+8], 1       ; не спаривается или только в U-конвеере
    CMP BYTE PTR [EBX], 1         ; спаривается
    CMP BYTE PTR [EBX+8], AL      ; спаривается

(Другая проблема, связанная с подобными инструкциями, выполняющимися на PMMX, заключается в том, что такие инструкции могут быть длинее семи байтов, а это приводит к невозможности раскодировки больше одной инструкции за такт, подробнее это объясняется в главе 12.)

9. Обе инструкции должны быть заранее загружены и раскодированы. Это объяснение в главе 8.

10. Есть специальные правила спаривания для инструкций MMX на PMMX:

  • MMX-сдвиг, инструкции упаковки или распаковки могут выполнять в любом конвеере, но не могут спариваться с другим MMX-сдвигом, инструкциями упаковки или распаковки.
  • MMX-инструкции умножения могут выполняться в любом конвеер, но не могут спариваться с другими MMX-инструкциями умножения. Они занимают 3 такта, и последние 2 такта могут перекрыть последующие инструкции, также как это делают инструкции плавающей запятой (смотри главу 24).
  • MMX-инструкция, обращающаяся к памяти или целочисленным регистрам может выполняться только в U-конвеер и не могут спариваться с не-MMX инструкцией.

10.2 Несовершенное спаривание

Бывают ситуации, когда две спаривающиеся инструкции не будут выполняться одновременно или будут частично рассинхронизированы во времени. Пока обе инструкции не выполняться (каждая в своем конвеере) ни одна другая инструкция не начнет выполняться.

Несовершенное спаривание возникает в следующих случаях:

  • Если вторая инструкция приводит к задержке AGU (глава 9).
  • Две инструкции не могут обращаться к одному и тому двойному слову в памяти одновременно:

    MOV AL, [ESI] / MOV BL, [ESI+1]

    Два операнда внутри одного и того же двойного слова, поэтому они не могут выполняться одновременно. Пара займет два такта для выполнения.

    MOV AL, [ESI+3] / MOV BL, [ESI+4]

    Эти два операнда находятся в разных двойных словах, поэтому они прекрасно спариваются и занимают всего один такт.

3. Правило 2 расширяет зону своего действия, если биты 2-4 обоих адресов одинаковы (конфликт банков кэша). Для адресов размеров в двойное слово это означает, что они не разность между обоими адресами не должна делиться на 32.

Примеры:

   MOV [ESI], EAX / MOV [ESI+32000], EBX ;  несовершенное спаривание
   MOV [ESI], EAX / MOV [ESI+32004], EBX ;  совершенное спаривание

Спариваемые целочисленные инструкции, которые не обращаются к памяти, требуют один такт для выполнения, кроме неправильно предсказанных переходов. Инструкции MOV, читающие или пишущие в память также занимают один такт, если данные находятся в кэше и правильно выравненны. Нет потери в скорости при использовании сложных способов адресации, такие как смещение и масштабирование.

Спариваемая целочисленная инструкция, которая читает из памяти, делает какие-то вычисления, а затем сохраняет результат в регистрах или флагах, занимает 2 такта (инструкции чтения/модифицирования).

Спариваемая целочисленная инструкция, которая читает из памяти, делает какие-то вычисления, а затем записывает результат обратно в память, занимает 3 такта (инструкции чтения/модифицирования/записи).

4. Если инструкция чтения/модифицирования/записи спаривается с инструкцией чтения/модифицирования или чтения/модифицирования/записи, тогда они спарятся несовершенно.

Количество тактов, которые потребуются для выполнения такой пары, даны в следующей таблице:

   Первая инструкция                    Вторая инструкция

                           MOV или регистр  чтение/изменение  чтение/изменение/запись
                         
   MOV или регистр              1                2                 3
    чтение/изменение            2                2                 3
   чтение/изменение/запись      3                4                 5

Пример:

ADD [mem1], EAX / ADD EBX, [mem2] ; 4 такта
ADD EBX, [mem2] / ADD [mem1], EAX ; 3 такта

B Когда две спаривающиеся инструкции требуют дополнительное время для выполнения из-за неоптимального использования кэша, невыровненности или неправильно предсказанного условного перехода, они будут выполнятся дольше, чем каждая инструкция, но меньше, чем сумма времени, требующаяся на выполнение каждой из них по отдельности.

6. Спариваемая инструкция плавающей запятой и следующая за ней FXCH повлекут несовершенное спаривание, если следующая инструкция не является инструкцией плавающей запятой.

Чтобы избежать несовершенного спаривания, вы должны знать, какие инструкции пойдут в U-конвеер, а какие - в V-конвеер. Вы можете выяснить это, просмотрев свой код и поискав инструкции, которые неспрариваются, или спариваются только в определенном конвеере, или не могут спариваться в силу одного из вышеизложенных правил.

Несовершенное спаривание можно зачастую избежать, реорганизовав свои инструкции.

Пример:

L1:     MOV     EAX,[ESI]
        MOV     EBX,[ESI]
        INC     ECX

Здесь две инструкции MOV формируют несовершенную пару, потому что обе обращаются к одной и той же области в памяти, поэтому последовательность займет 3 такта. Вы можете улучшить этот код, реорганизовав инструкции так, чтобы 'INC ECX' спаривалась с одной из инструкции MOV.

L2:     MOV     EAX,OFFSET A
        XOR     EBX,EBX

        INC     EBX
        MOV     ECX,[EAX]
        JMP     L1

Пара 'INC EBX / MOV ECX,[EAX]' несовершенная, потому что следующая инструкция приводит к задержке AGI. Последовательность занимает 4 такта. Если вы вставите NOP или какую-нибудь другую инструкцию, чтобы 'MOV ECX,[EAX]' спаривался с 'JMP L1', последовательность займет только три такта.

Следующий пример выполняется в 16-ти битном режима, предполагается,что SP делится на 4:

L3:     PUSH    AX
        PUSH    BX
        PUSH    CX

        PUSH    DX
        CALL    FUNC

Инструкции PUSH формируют две несовершенные пары, потому что оба операнда в каждой паре обращаются к одному и тому же слову в памяти. 'PUSH BX' могла бы совершенно спариться с PUSH CX (потому что они находятся по разные стороны от границы, отделяющей двойные слова друг от друга), но этого не происходит, потому что она уже спарена с PUSH AX. Поэтому последовательность занимает 5 тактов. Если вы вставите NOP или другую инструкцию, чтобы 'PUSH BX' спаривалась с 'PUSH CX', а 'PUSH DX' с 'CALL FUNC', последовательность займет только 3 такта. Другой путь разрешения данной проблемы - это убедиться, что SP не кратен четырем. Правда, узнать это в 16-ти битному режиме довольно сложно, поэтому лучший выход - использовать 32-х битный режим.

2002-2013 (c) wasm.ru