Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

int i, n; double *X; double * Y; double DA;

for (1=0; i<n; 1++]

Y[i] = Y[i] - DA * X[i]

Oh является ключевым участком при решении линейных уравнений (алгоритм DAXPY).

DSIZE

размер данных

EAX, [

количество элементов

ESI,

указатель на X

EDI,

указатель на Y

ECX, ECX

ESI,

ESI+DSIZE*EAX]

указывает на конец х

ECX, EAX

EDI,

EDI+DSIZE*EAX]

указывает на конец Y

SHORT

; тестируем N == 0 или нет

DSIZE

[DA]

FMUL

DSIZE

[ESI+DSIZE*ECX]

DA * Х[0]

SHORT

переходим к циклу

DSIZE

[DA]

FMUL

DSIZE

[ESI+DSIZE*ECX]

DA * Х[1]

FXCH

; получаем старый резуль

FSTP

DSIZE

[EDI+DSIZE*ECX-

DSIZE]

; сохраняем Y[i]

FSUBR

DSIZE

[EDI+DSIZE*ECX]

; вычитаем из Y[i]

; увеличиваем значение

; индекса на 1

; цикл

FSTP

DSIZE

[EDI+DSIZE*ECX-

-DSIZE]

; сохраняем последни

результат

Здесь используются те же методы, что и в примере пункта 6.25.1.5: четчик цикла в качестве индекса и последовательность отрицательных значений от -N до 0. Коней выполнения одной операции пересекается с началом выполнени другой.

Смешение различных инструкций плавающей запятой работает прекрасно: задер** в 2 такта между FMUL и FSUBR заполняется FSTP предыдущего результата. Задерж в 3 такта между FSUBR и FSTP заполняется инструкциями управления циклом и первыми двумя инструкциями следующей итерации. Задержки AGI удалось избежать благода" чтению в первом такте после изменения индекса только тех параметров, которые о индекса не зависят.

Это решение занимает 6 тактов на операцию!

6.25.1.11. Развертывание циклов с инструкциями с плавающей запятой (Р1 и PMl Цикл DAXPY, развернутый в 3 раза, довольно сложен:

r3?.i.-..9."J."..V.lf." Э.Р?! семейства Pentium Пример

DSIZE = 8 IF DSIZE EQ SHIFTCOUNT = ELSE

SHIFTCOUNT = ENDIF

MOV MOV SHL JZ MOV SUB MOV SUB SUB TEST FLD JNS FMUL FLD FMUL FXCH FSUBR FXCH FLD FMUL FXCH FSUBR FXCH FSTP FSUBR FXCH FSTP FLD FXCH FSTP ADD JS

FMUL FSUBR SUB JZ FLD FMUL FXCH FSTP

размер данных

; количество элементов

; погрешность счетчика

; DSIZE*N

; N = О

; указатель на X

; (3-N)*DSIZE

; указатель на Y конец указателя - погрешнос

; первый x

; меньше чем 4 операции

еах, [N] есх, 3*dsize еах, shiftcount L4

esi, [x] есх, еах edi, [Y] esi, есх edi, есх есх, есх

dsize ptr [esi+ecx] short L2 dsize ptr [da] dsize ptr [esi+ecx+dsize] dsize ptr [da]

dsize ptr (edi+ecxj

dsize ptr [esi+ecx+2*dsize;

dsize ptr [da]

DSIZE PTR [EDl+ECX+DSIZE] ST(2)

DSIZE PTR [EDI+ECX]

DSIZE PTR [EDI+ECX+2*DSIZE]

DSIZE PTR [EDI+ECX+DSIZE] DSIZE PTR [ESI+ECX+3*DSIZE]

DSIZE PTR [EDI+ECX+2*DSIZE] ECX, 3*DSIZE LI

DSIZE PTR [DA]

DSIZE PTR [EDI+ECX] ECX, 2*DSIZE .; изменяем погрешность указатех

SHORT L3 ; закончили

DSIZE PTR [DA] ; начинаем новую операцию

DSIZE PTR [ESI+ECX+3*DSIZE]

; цикл

; завершаем оставшуюся операц

dsize PTR [edi+ecx+2*dsize]



438 Ассемблер в задачах защиты uнфopмaцj,

FSUBR

DSIZE

PTR [EDI+ECX+3*

DSIZE]

ECX, 1

*DSIZE

SHORT

DSIZE

PTR [DA]

FMUL

DSIZE

PTR [ESI+ECX+3*

DSIZE]

FXCH

FSTP

DSIZE

PTR [EDI+ECX+2*

DSIZE]

FSUBR

DSIZE

PTR [EDI+ECX+3*

DSIZE]

ECX, 1*DSIZE

FSTP

DSIZE

PTR [EDI+ECX+2*

DSIZE]

закончили

L3: L4:

Причина, по которой рассматривается вопрос, как развернуть цикл в три раза, не в том, чтобы порекомендовать подобный подход, а в том, чтобы продемонстрровать, как это сложно! Нужно быть готовым провести значительное количество времени, отлаживая и проверяя код со степенью развертывания меньше 4. Есть несколько проблем, о которых нужно позаботиться: в большинстве случаев невозможно устранить все задержки в цикле с инструкциями плавающей запятой, если только не свернуть его (т. е. в конце цикла будут операции, выполнение которых закончится в конце следующего повторения). Последний FLD в основном цикле примера является началом первой операции в следующей итерации. Неплохо сделать реализацию, с методикой пунктов 6.25.1.8 и 6.25.1.9, но это не рекомендуется делать с инструкциями плавающей запятой, потому что чтение дополнительного значения за границой массива может сгенерировать исключение ненормализованного операнда, если после массива не находится число с плавающей запятой. Чтобы избежать этого, приходиться делать по крайней мере на одну операцию больше после основного цикла.

Количество операций, которое необходимо выполнить снаружи развернутого цикла, как правило, будет равно N MODULE R, где N - количество операций, а R - коэффициент развернутости цикла. Но в случае со свернутым циклом, нужно сделать на одну операцию больше, то есть (N-1) MODULO R + 1 в силу вышеуказанных причин.

Обычно подготовительные операции выполняются до основного цикла, но здесь необходимо делать их позже в силу двух причин: одна причина - это забота об оставшемся операнде (из-за свертывания). Другая причина состоит в том, что вычисление количества дополнительных операций требует деления, если R не является степенью 2-n а деление занимает много времени. Дополнительные операции после основного п№ решают эту проблему.

Другая задача - это высчитать, как влиять на счетчик цикла, чтобы он изменил знак в пра-вильный момент, и привести в порядок базовые указатели. Наконец, следует убедиться, чт" оставшийся от свертьшания операнд был обработан верно для всех значений N.

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

Теперь рассмотрим, насколько проще разворачивать цикл на 4 операции.

£"....4:.19 процессоров семейства Pentium

DSIZE = 8 MOV MOV MOV XOR LEA SUB LEA TEST JZ FLD FMUL FSUBR INC FSTP TEST JZ FLD FMUL FLD FMUL FXCH FSUBR FXCH FSUBR FXCH FSTP FSTP ADD TEST JZ FLD FLD FMUL FLD FMUL FLD FMUL FXCH FSUBR FXCH FMUL FXCH FSUBR FXCH FSUBR

; размер данных ; количество элементов ; указатель на X ; указатель на Y

; указывает на конец X

; -N

; указывает на конец Y

; тестируем N на нечетност

; делаем нечетную операцик

ЕАХ, [N] ESI, [X] EDI, [Y] ЕСХ, ЕСХ

ESI, [ESI+DSIZE*EAX] ЕСХ, ЕАХ

EDI, [EDI+DSI2E*EAX] AL, 1

SHORT LI DSIZE PTR [DA] DSIZE PTR [ESI+DSIZE*ECX] DSIZE PTR [EDI+DSIZE*ECX]

ECX ; увеличиваем значение счетчи

DSIZE PTR [EDI+DSIZE*ECX-DSIZE]

AL,2 ; можно ли сделать еще 2 операции

DSIZE PTR [DA] ; N MOD 4=2 или 3. Делаем еще д

DSIZE PTR [ESI+DSIZE*ECX] DSIZE PTR [DA]

DSIZE PTR [ESI+DSIZE*ECX+DSIZE]

DSIZE PTR [EDI+DSIZE*ECX]

DSIZE PTR [EDI+DSIZE*ECX+DSIZE]

DSIZE PTR [EDI+DSIZE*ECX]

DSIZE PTR [EDI+DSIZE*ECX+DSIZE]

ECX, 2 ; счетчик не делится 4

ECX, ECX

L4 ; больше операций нет

DSIZE PTR [DA]

DSIZE PTR [ESI+DSIZE*ECX] ST,ST(1)

DSIZE PTR [ESI+DSIZE*ECX+DSIZE] ST,ST(2)

DSIZE PTR [ESI+DSIZE*ECX+2*DSIZE]

ST,ST(3)

ST(2)

DSIZE PTR [EDI+DSIZE*ECX] ST(3)

DSIZE PTR [ESI+DSIZE*ECX+3*DSIZE]

DSIZE PTR [EDI+DSIZE*ECX+DSIZE] ST(2)

DSIZE PTR [EDI+DSIZE*ECX+2*DSIZE]



440 Ассемблер в задачах защиты информац

FXCH

FSUBR

DSIZE

[EDI+DSIZE*ECX+3*DSIZE]

FXCH

ST(3)

FSTP

DSIZE

[EDI+DSIZE*ECX]

FSTP

DSIZE

[EDI+DSIZE*ECX+2*DSIZE]

FSTP

DSIZE

[EDI+DSIZE*ECX+DSIZE]

FSTP

DSIZE

[EDI + DSIZE*ECX + 3*t)SIZE]

ECX, 4

; увеличиваем

; цикл

L4 :

Обычно довольно легко добиться отсутствия задержек в Щ1кле, развернутом на 4 и нет нужды в свертывании последней операщ1И. Количество дополнительных операций, которые нужно сделать за пределами основного цикла равно N MODULO 4, что можно легко посчитать без деления, просто протестировав два младших бита в N. Дополнительные операции делаются до основного цикла, а не после, чтобы сделать обработку счетчика цикла проще.

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

В качестве основной рекомендации, можно принять то, что если N велико или если сворачивание цикла без развертывания не может удалить некоторых задержек, следует развернуть критические целочисленные циклы в два раза, а {щклы с инструкциями плавающей запятой в 4 раза.

6.25.2. Циклы в РРго, Р2 и РЗ

в предыдущей части раздела (6.25.1) описывалось, как использовать свертьгаание и развертывание циклов, чтобы улучшить спаривание в Р1 и РММХ. На РРго, Р2 и РЗ нет никакой причины делать это благодаря механизму переупорядочевания инструкиий-Но здесь есть другие проблемы, о которых надо заботиться, связанные с границами БДИ и задержкой чтения регистров.

6.25.2.1. Рассмотрим те же примеры, что и в первой части раздела 6.25: процедуру-которая считывает целые числа из массива, изменяет их знак, и сохраняет результаты в другой массив.

На С эта процедура выглядела бы так:

void ChangeSign (int * А, int * В, int N)

int i ;

for (i=0; i<N; B[i] = -A[i];

-ва б-..9."У.:!....?" процессоров семейства Pentium

Ее ассемблерный вариант:

ChangeSign PROC NEAR

PUSH PUSH EQU EQU EQU MOV JECXZ MOV MOV CLD LODSD NEG STOSD LOOP POP POP RET ChangeSign

LI ;

L2 ;

ESI EDI

DWORD PTR [ESP-H2] DWORD PTR [ESP-H6] DWORD PTR [ESP-f20] ECX, [N] L2

ESI, [A] EDI, [B]

ENDP

Это выглядит как довольно красивое решение, но, естественно, не самое оптималь ное, потому что он использует инструкции LOOP, LODSD и STOSD, которые генериру ют много мопов. Одна итеращм цикла занимает 6 - 7 тактов, если все данные находятс в кэше первого уровня. Если избегать данных инструкций, получим:

ALIGN L1:

ECX,

JECXZ

ESI ,

EDI,

EAX,

[ESI]

ESI,

[EDI], EAX

EDI,

len=2, p2rESIwEAX

len=3, pOlrwESIwF

len=2, pOlrwEAXwF

len=2, p4rEAX, p3rEDI

len=3, pOlrwEDIwF

len=l, pOlrwECXwF

len=2, plrF

Комментарии интерпретируются следующим образом: инструкция MOV ЕАХ [ESI оаита длиной, генерирует один моп для порта 2, который читает ESI и пишет (пере овывает) в ЕАХ. Эта информация требуется для анализа возможных узких мест.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88